[CFE] Coverage tool handles comments ignoring coverage
Allow comments to ignore some coverage block.
This is a step towards being able to (fake) push everything to 100%
covered, making a regression be nicely marked.
Also running `pkg/front_end/tool/coverage_merger.dart` with `--comment`
will add ignore comments.
Change-Id: I798dc2673eb71247af16356a7bd28d6629285a16
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/372501
Commit-Queue: Jens Johansen <jensj@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/front_end/lib/src/kernel/constant_collection_builders.dart b/pkg/front_end/lib/src/kernel/constant_collection_builders.dart
index 1efe542..bef9a2e 100644
--- a/pkg/front_end/lib/src/kernel/constant_collection_builders.dart
+++ b/pkg/front_end/lib/src/kernel/constant_collection_builders.dart
@@ -105,7 +105,7 @@
if (parts.last is List<Constant>) {
lastPart = parts.last as List<Constant>;
} else {
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
parts.add(lastPart = <Constant>[]);
}
Constant value = evaluator.ensureIsSubtype(constant, elementType, context);
@@ -177,7 +177,7 @@
if (parts.last is List<Constant>) {
lastPart = parts.last as List<Constant>;
} else {
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
parts.add(lastPart = <Constant>[]);
}
Constant value = evaluator.ensureIsSubtype(constant, elementType, context);
@@ -291,7 +291,7 @@
if (parts.last is List<ConstantMapEntry>) {
lastPart = parts.last as List<ConstantMapEntry>;
} else {
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
parts.add(lastPart = <ConstantMapEntry>[]);
}
if (!evaluator.hasPrimitiveEqual(key,
diff --git a/pkg/front_end/lib/src/kernel/constant_evaluator.dart b/pkg/front_end/lib/src/kernel/constant_evaluator.dart
index 1be0017..00176d6 100644
--- a/pkg/front_end/lib/src/kernel/constant_evaluator.dart
+++ b/pkg/front_end/lib/src/kernel/constant_evaluator.dart
@@ -86,6 +86,7 @@
constantsTransformer.constantEvaluator.visitedLibraries);
}
+// Coverage-ignore(suite): Only run from expression compilation.
void transformProcedure(
Procedure procedure,
Target target,
@@ -208,6 +209,8 @@
transformFieldList(library.fields, library);
if (!keepFields) {
+ // Coverage-ignore: `keepFields` is currently always true. Maybe it should
+ // just be removed?
// The transformer API does not iterate over `Library.additionalExports`,
// so we manually delete the references to shaken nodes.
library.additionalExports.removeWhere((Reference reference) {
@@ -218,6 +221,7 @@
_exhaustivenessCache = null;
}
+ // Coverage-ignore(suite): Only run from expression compilation.
Procedure convertProcedure(Procedure node) {
_exhaustivenessCache =
new CfeExhaustivenessCache(constantEvaluator, node.enclosingLibrary);
@@ -2397,7 +2401,9 @@
final List<LocatedMessage> contextMessages = <LocatedMessage>[
locatedMessageActualError
];
- if (result.context != null) contextMessages.addAll(result.context!);
+ if (result.context != null) {
+ contextMessages.addAll(result.context!);
+ }
if (contextNode != null && contextNode != result.node) {
contextMessages.add(
createLocatedMessage(contextNode, messageConstEvalContext));
@@ -2503,7 +2509,7 @@
return status.error;
} else if (status is ReturnStatus) {
if (status.value == null) return null;
- // Should not be reachable.
+ // Coverage-ignore: Should not be reachable.
return createEvaluationErrorConstant(
constructor,
templateConstEvalError
@@ -3002,7 +3008,7 @@
final Class klass = constructor.enclosingClass;
if (klass.isAbstract) {
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
return createExpressionErrorConstant(
node, templateAbstractClassInstantiation.withArguments(klass.name));
}
@@ -3060,7 +3066,7 @@
// Fill in any missing type arguments with "dynamic".
for (int i = typeArguments.length; i < klass.typeParameters.length; i++) {
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
typeArguments.add(const DynamicType());
}
@@ -3096,7 +3102,7 @@
if (constructor.function.body != null &&
constructor.function.body is! EmptyStatement &&
!enableConstFunctions) {
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
return createExpressionErrorConstant(
node, messageConstConstructorWithBody);
} else if (constructor.isExternal) {
@@ -3268,8 +3274,9 @@
AbortConstant? error = checkAssert(init.statement);
if (error != null) return error;
} else {
+ // Coverage-ignore: Probably unreachable.
// InvalidInitializer or new Initializers.
- // Probably unreachable. InvalidInitializer is (currently) only
+ // InvalidInitializer is (currently) only
// created for classes with no constructors that doesn't have a
// super that takes no arguments. It thus cannot be const.
// Explicit constructors with incorrect super calls will get a
@@ -3851,7 +3858,6 @@
if (right is BoolConstant || right is UnevaluatedConstant) {
return right;
}
-
return createEvaluationErrorConstant(
node,
templateConstEvalInvalidBinaryOperandType.withArguments(
@@ -3873,7 +3879,6 @@
if (right is BoolConstant || right is UnevaluatedConstant) {
return right;
}
-
return createEvaluationErrorConstant(
node,
templateConstEvalInvalidBinaryOperandType.withArguments(
@@ -3921,8 +3926,8 @@
@override
Constant visitInstanceGet(InstanceGet node) {
if (node.receiver is ThisExpression) {
- // Probably unreachable unless trying to evaluate non-const stuff as
- // const.
+ // Coverage-ignore: Probably unreachable unless trying to evaluate
+ // non-const stuff as const.
// Access "this" during instance creation.
if (instanceBuilder == null) {
return createEvaluationErrorConstant(
@@ -3939,7 +3944,7 @@
// Meant as a "stable backstop for situations where Fasta fails to
// rewrite various erroneous constructs into invalid expressions".
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
return createEvaluationErrorConstant(
node,
templateConstEvalError.withArguments(
@@ -4249,7 +4254,7 @@
} else if (defaultValue is NullConstant) {
boolConstant = nullConstant;
} else {
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
boolConstant = falseConstant;
}
} else {
@@ -4287,8 +4292,8 @@
}
return stringConstant;
}
- // Unreachable until fromEnvironment is added to other classes in dart:core
- // than bool, int and String.
+ // Coverage-ignore: Unreachable until fromEnvironment is added to other
+ // classes in dart:core than bool, int and String.
throw new UnsupportedError(
'Unexpected fromEnvironment constructor: $target');
}
@@ -4639,7 +4644,7 @@
return canonicalize(
new InstantiationConstant(constant, convertTypes(types)));
} else {
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
return createEvaluationErrorConstant(
node,
templateConstEvalError.withArguments(
@@ -4650,7 +4655,7 @@
}
// The inner expression in an instantiation can never be null, since
// instantiations are only inferred on direct references to declarations.
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
return createEvaluationErrorConstant(
node,
templateConstEvalError.withArguments(
@@ -4682,7 +4687,7 @@
return canonicalize(
new TypedefTearOffConstant(typeParameters, constant, typeArguments));
} else {
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
return createEvaluationErrorConstant(
node,
templateConstEvalError.withArguments(
@@ -4827,7 +4832,7 @@
if (targetingJavaScript && !result) {
if (constantType is InterfaceType &&
constantType.classNode == typeEnvironment.coreTypes.intClass) {
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
// With JS semantics, an integer is also a double.
result = typeEnvironment.isSubtypeOf(
new InterfaceType(typeEnvironment.coreTypes.doubleClass,
@@ -5059,7 +5064,7 @@
return makeBoolConstant(a > b);
}
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
return createExpressionErrorConstant(node,
templateNotConstantExpression.withArguments("Binary '$op' operation"));
}
@@ -5214,7 +5219,9 @@
@override
ExecutionStatus visitIfStatement(IfStatement node) {
Constant condition = evaluate(node.condition);
- if (condition is AbortConstant) return new AbortStatus(condition);
+ if (condition is AbortConstant) {
+ return new AbortStatus(condition);
+ }
assert(condition is BoolConstant);
if ((condition as BoolConstant).value) {
return node.then.accept(this);
@@ -5251,7 +5258,9 @@
}
}
- if (condition is AbortConstant) return new AbortStatus(condition);
+ if (condition is AbortConstant) {
+ return new AbortStatus(condition);
+ }
assert(condition is BoolConstant);
return const ProceedStatus();
}
@@ -5285,7 +5294,9 @@
@override
ExecutionStatus visitSwitchStatement(SwitchStatement node) {
final Constant value = evaluate(node.expression);
- if (value is AbortConstant) return new AbortStatus(value);
+ if (value is AbortConstant) {
+ return new AbortStatus(value);
+ }
for (SwitchCase switchCase in node.cases) {
if (switchCase.isDefault) return switchCase.body.accept(this);
@@ -5376,7 +5387,9 @@
if (status is! ProceedStatus) return status;
condition = evaluate(node.condition);
}
- if (condition is AbortConstant) return new AbortStatus(condition);
+ if (condition is AbortConstant) {
+ return new AbortStatus(condition);
+ }
assert(condition is BoolConstant);
return const ProceedStatus();
}
diff --git a/pkg/front_end/lib/src/kernel/constant_int_folder.dart b/pkg/front_end/lib/src/kernel/constant_int_folder.dart
index ee1fa41..43fc143 100644
--- a/pkg/front_end/lib/src/kernel/constant_int_folder.dart
+++ b/pkg/front_end/lib/src/kernel/constant_int_folder.dart
@@ -85,7 +85,7 @@
case '~':
return new IntConstant(~operand.value);
default:
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
return evaluator.createExpressionErrorConstant(
node,
templateNotConstantExpression
@@ -136,7 +136,7 @@
case '>':
return evaluator.makeBoolConstant(a > b);
default:
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
return evaluator.createExpressionErrorConstant(
node,
templateNotConstantExpression
@@ -202,7 +202,7 @@
int intValue = _toUint32(operand.value);
return new DoubleConstant(_truncate32(~intValue).toDouble());
default:
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
return evaluator.createExpressionErrorConstant(
node,
templateNotConstantExpression
@@ -259,7 +259,7 @@
case '>':
return evaluator.makeBoolConstant(a > b);
default:
- // Probably unreachable.
+ // Coverage-ignore: Probably unreachable.
return evaluator.createExpressionErrorConstant(
node,
templateNotConstantExpression
diff --git a/pkg/front_end/test/coverage_suite.dart b/pkg/front_end/test/coverage_suite.dart
index d0413cb..50dc957 100644
--- a/pkg/front_end/test/coverage_suite.dart
+++ b/pkg/front_end/test/coverage_suite.dart
@@ -68,6 +68,8 @@
Uri.base.resolve(".dart_tool/package_config.json"),
coverageTmpDir.uri,
silent: true,
+ extraCoverageIgnores: ["coverage-ignore(suite):"],
+ extraCoverageBlockIgnores: ["coverage-ignore-block(suite):"],
);
if (coverageData == null) throw "Failure in coverage.";
@@ -126,6 +128,7 @@
int hitCount = coverageEntry.value.hitCount;
int missCount = coverageEntry.value.missCount;
double percent = (hitCount / (hitCount + missCount) * 100);
+ if (percent.isNaN) percent = 100;
if (options.updateExpectations) {
updatedExpectations.writeln(" // $percent%.");
updatedExpectations.writeln(" \"${coverageEntry.key}\": "
@@ -142,6 +145,7 @@
double expectedPercent = (expected.hitCount /
(expected.hitCount + expected.missCount) *
100);
+ if (expectedPercent.isNaN) expectedPercent = 100;
int requireAtLeast = expectedPercent.floor();
pass = percent >= requireAtLeast;
if (!pass) {
diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart
index d41bbc8..b1f2449 100644
--- a/pkg/front_end/test/coverage_suite_expected.dart
+++ b/pkg/front_end/test/coverage_suite_expected.dart
@@ -8,25 +8,20 @@
// using out/ReleaseX64/dart-sdk/bin/dart (which for instance makes a
// difference for compute_platform_binaries_location.dart).
const Map<String, ({int hitCount, int missCount})> _expect = {
- // 18.53448275862069%.
+ // 18.614718614718615%.
"package:front_end/src/api_prototype/compiler_options.dart": (
hitCount: 43,
- missCount: 189,
+ missCount: 188,
),
// 89.1891891891892%.
"package:front_end/src/api_prototype/experimental_flags.dart": (
hitCount: 66,
missCount: 8,
),
- // 54.07925407925408%.
- "package:front_end/src/api_prototype/experimental_flags_generated.dart": (
- hitCount: 232,
- missCount: 197,
- ),
- // 33.33333333333333%.
+ // 100.0%.
"package:front_end/src/api_prototype/file_system.dart": (
hitCount: 2,
- missCount: 4,
+ missCount: 0,
),
// 6.666666666666667%.
"package:front_end/src/api_prototype/incremental_kernel_generator.dart": (
@@ -41,22 +36,22 @@
// 0.0%.
"package:front_end/src/api_prototype/language_version.dart": (
hitCount: 0,
- missCount: 67,
+ missCount: 65,
),
- // 3.903903903903904%.
+ // 3.927492447129909%.
"package:front_end/src/api_prototype/lowering_predicates.dart": (
hitCount: 13,
- missCount: 320,
+ missCount: 318,
),
- // 25.0%.
+ // 27.710843373493976%.
"package:front_end/src/api_prototype/memory_file_system.dart": (
hitCount: 23,
- missCount: 69,
+ missCount: 60,
),
- // 38.46153846153847%.
+ // 38.83495145631068%.
"package:front_end/src/api_prototype/standard_file_system.dart": (
hitCount: 40,
- missCount: 64,
+ missCount: 63,
),
// 0.0%.
"package:front_end/src/api_prototype/summary_generator.dart": (
@@ -98,10 +93,10 @@
hitCount: 70,
missCount: 29,
),
- // 90.1639344262295%.
+ // 93.22033898305084%.
"package:front_end/src/base/compiler_context.dart": (
hitCount: 55,
- missCount: 6,
+ missCount: 4,
),
// 100.0%.
"package:front_end/src/base/configuration.dart": (
@@ -143,10 +138,10 @@
hitCount: 96,
missCount: 3,
),
- // 50.55718475073314%.
+ // 50.67607289829512%.
"package:front_end/src/base/incremental_compiler.dart": (
hitCount: 862,
- missCount: 843,
+ missCount: 839,
),
// 0.0%.
"package:front_end/src/base/incremental_serializer.dart": (
@@ -183,15 +178,15 @@
hitCount: 0,
missCount: 29,
),
- // 39.86486486486486%.
+ // 40.75993091537133%.
"package:front_end/src/base/processed_options.dart": (
hitCount: 236,
- missCount: 356,
+ missCount: 343,
),
- // 80.62563067608475%.
+ // 84.01682439537329%.
"package:front_end/src/base/scope.dart": (
hitCount: 799,
- missCount: 192,
+ missCount: 152,
),
// 73.07692307692307%.
"package:front_end/src/base/ticker.dart": (
@@ -218,10 +213,10 @@
hitCount: 0,
missCount: 17,
),
- // 64.44444444444444%.
+ // 72.5%.
"package:front_end/src/builder/builder.dart": (
hitCount: 29,
- missCount: 16,
+ missCount: 11,
),
// 100.0%.
"package:front_end/src/builder/builder_mixins.dart": (
@@ -253,10 +248,10 @@
hitCount: 2,
missCount: 0,
),
- // 50.0%.
+ // 100.0%.
"package:front_end/src/builder/extension_builder.dart": (
hitCount: 4,
- missCount: 4,
+ missCount: 0,
),
// 100.0%.
"package:front_end/src/builder/extension_type_declaration_builder.dart": (
@@ -343,15 +338,15 @@
hitCount: 24,
missCount: 0,
),
- // 34.146341463414636%.
+ // 37.83783783783784%.
"package:front_end/src/builder/omitted_type_builder.dart": (
hitCount: 28,
- missCount: 54,
+ missCount: 46,
),
// 0.0%.
"package:front_end/src/builder/omitted_type_declaration_builder.dart": (
hitCount: 0,
- missCount: 13,
+ missCount: 5,
),
// 89.74358974358975%.
"package:front_end/src/builder/prefix_builder.dart": (
@@ -368,10 +363,10 @@
hitCount: 186,
missCount: 50,
),
- // 77.77777777777779%.
+ // 82.35294117647058%.
"package:front_end/src/builder/type_builder.dart": (
hitCount: 56,
- missCount: 16,
+ missCount: 12,
),
// 90.0%.
"package:front_end/src/builder/type_declaration_builder.dart": (
@@ -388,15 +383,10 @@
hitCount: 2,
missCount: 0,
),
- // 73.0892742453436%.
- "package:front_end/src/codes/cfe_codes_generated.dart": (
- hitCount: 1138,
- missCount: 419,
- ),
- // 83.68336025848141%.
+ // 85.0574712643678%.
"package:front_end/src/codes/type_labeler.dart": (
hitCount: 518,
- missCount: 101,
+ missCount: 91,
),
// 71.23287671232876%.
"package:front_end/src/compute_platform_binaries_location.dart": (
@@ -408,10 +398,10 @@
hitCount: 16,
missCount: 0,
),
- // 92.34972677595628%.
+ // 93.37016574585635%.
"package:front_end/src/dill/dill_class_builder.dart": (
hitCount: 169,
- missCount: 14,
+ missCount: 12,
),
// 86.74698795180723%.
"package:front_end/src/dill/dill_extension_builder.dart": (
@@ -433,10 +423,10 @@
hitCount: 129,
missCount: 25,
),
- // 83.12342569269522%.
+ // 84.61538461538461%.
"package:front_end/src/dill/dill_library_builder.dart": (
hitCount: 330,
- missCount: 67,
+ missCount: 60,
),
// 77.03349282296651%.
"package:front_end/src/dill/dill_loader.dart": (
@@ -468,70 +458,70 @@
hitCount: 0,
missCount: 128,
),
- // 92.09016940109377%.
+ // 92.1639300493926%.
"package:front_end/src/kernel/body_builder.dart": (
hitCount: 6904,
- missCount: 593,
+ missCount: 587,
),
- // 70.40816326530613%.
+ // 91.26984126984127%.
"package:front_end/src/kernel/body_builder_context.dart": (
hitCount: 345,
- missCount: 145,
+ missCount: 33,
),
- // 36.44736842105264%.
+ // 36.83510638297872%.
"package:front_end/src/kernel/collections.dart": (
hitCount: 277,
- missCount: 483,
+ missCount: 475,
),
- // 91.8854415274463%.
+ // 92.54807692307693%.
"package:front_end/src/kernel/combined_member_signature.dart": (
hitCount: 385,
- missCount: 34,
+ missCount: 31,
),
// 61.68831168831169%.
"package:front_end/src/kernel/const_conditional_simplifier.dart": (
hitCount: 95,
missCount: 59,
),
- // 67.65676567656766%.
+ // 69.72789115646259%.
"package:front_end/src/kernel/constant_collection_builders.dart": (
hitCount: 205,
- missCount: 98,
+ missCount: 89,
),
- // 82.66337300696159%.
+ // 85.85694379934975%.
"package:front_end/src/kernel/constant_evaluator.dart": (
- hitCount: 3681,
- missCount: 772,
+ hitCount: 3697,
+ missCount: 609,
),
- // 92.04545454545455%.
+ // 97.59036144578313%.
"package:front_end/src/kernel/constant_int_folder.dart": (
hitCount: 243,
- missCount: 21,
+ missCount: 6,
),
// 95.11278195488721%.
"package:front_end/src/kernel/constructor_tearoff_lowering.dart": (
hitCount: 253,
missCount: 13,
),
- // 74.57098283931357%.
+ // 75.0392464678179%.
"package:front_end/src/kernel/exhaustiveness.dart": (
hitCount: 478,
- missCount: 163,
+ missCount: 159,
),
- // 79.7660448940879%.
+ // 79.81651376146789%.
"package:front_end/src/kernel/expression_generator.dart": (
hitCount: 2523,
- missCount: 640,
+ missCount: 638,
),
// 100.0%.
"package:front_end/src/kernel/expression_generator_helper.dart": (
hitCount: 36,
missCount: 0,
),
- // 90.27777777777779%.
+ // 93.97590361445783%.
"package:front_end/src/kernel/forest.dart": (
hitCount: 390,
- missCount: 42,
+ missCount: 25,
),
// 94.4927536231884%.
"package:front_end/src/kernel/forwarding_node.dart": (
@@ -548,10 +538,10 @@
hitCount: 218,
missCount: 0,
),
- // 87.52834467120182%.
+ // 87.92710706150342%.
"package:front_end/src/kernel/hierarchy/extension_type_members.dart": (
hitCount: 386,
- missCount: 55,
+ missCount: 53,
),
// 50.77720207253886%.
"package:front_end/src/kernel/hierarchy/hierarchy_builder.dart": (
@@ -578,25 +568,25 @@
hitCount: 248,
missCount: 155,
),
- // 52.24719101123596%.
+ // 60.3896103896104%.
"package:front_end/src/kernel/implicit_field_type.dart": (
hitCount: 93,
- missCount: 85,
+ missCount: 61,
),
- // 2.941176470588235%.
+ // 5.555555555555555%.
"package:front_end/src/kernel/implicit_type_argument.dart": (
hitCount: 1,
- missCount: 33,
+ missCount: 17,
),
- // 46.484375%.
+ // 47.25972994440032%.
"package:front_end/src/kernel/internal_ast.dart": (
hitCount: 595,
- missCount: 685,
+ missCount: 664,
),
- // 74.13793103448276%.
+ // 78.18181818181819%.
"package:front_end/src/kernel/invalid_type.dart": (
hitCount: 43,
- missCount: 15,
+ missCount: 12,
),
// 55.55555555555556%.
"package:front_end/src/kernel/kernel_constants.dart": (
@@ -608,10 +598,10 @@
hitCount: 285,
missCount: 3,
),
- // 81.10175975516451%.
+ // 81.35072908672295%.
"package:front_end/src/kernel/kernel_target.dart": (
hitCount: 1060,
- missCount: 247,
+ missCount: 243,
),
// 61.111111111111114%.
"package:front_end/src/kernel/kernel_variable_builder.dart": (
@@ -636,17 +626,17 @@
// 0.0%.
"package:front_end/src/kernel/macro/identifiers.dart": (
hitCount: 0,
- missCount: 132,
+ missCount: 120,
),
// 0.0%.
"package:front_end/src/kernel/macro/introspectors.dart": (
hitCount: 0,
- missCount: 573,
+ missCount: 549,
),
- // 0.19047619047619047%.
+ // 0.1932367149758454%.
"package:front_end/src/kernel/macro/macro.dart": (
hitCount: 2,
- missCount: 1048,
+ missCount: 1033,
),
// 0.0%.
"package:front_end/src/kernel/macro/offsets.dart": (
@@ -658,10 +648,10 @@
hitCount: 0,
missCount: 230,
),
- // 89.23611111111111%.
+ // 91.13475177304964%.
"package:front_end/src/kernel/member_covariance.dart": (
hitCount: 257,
- missCount: 31,
+ missCount: 25,
),
// 39.473684210526315%.
"package:front_end/src/kernel/resource_identifier.dart": (
@@ -673,20 +663,20 @@
hitCount: 16,
missCount: 89,
),
- // 19.753086419753085%.
+ // 20.77922077922078%.
"package:front_end/src/kernel/try_constant_evaluator.dart": (
hitCount: 16,
- missCount: 65,
+ missCount: 61,
),
// 94.27402862985686%.
"package:front_end/src/kernel/type_algorithms.dart": (
hitCount: 922,
missCount: 56,
),
- // 90.20618556701031%.
+ // 92.10526315789474%.
"package:front_end/src/kernel/type_builder_computer.dart": (
hitCount: 175,
- missCount: 19,
+ missCount: 15,
),
// 37.93103448275862%.
"package:front_end/src/kernel/utils.dart": (
@@ -698,10 +688,10 @@
hitCount: 18,
missCount: 14,
),
- // 28.79581151832461%.
+ // 28.947368421052634%.
"package:front_end/src/kernel_generator_impl.dart": (
hitCount: 55,
- missCount: 136,
+ missCount: 135,
),
// 0.0%.
"package:front_end/src/macros/isolate_macro_serializer.dart": (
@@ -733,20 +723,20 @@
hitCount: 163,
missCount: 40,
),
- // 92.1875%.
+ // 93.38129496402877%.
"package:front_end/src/source/diet_listener.dart": (
hitCount: 649,
- missCount: 55,
+ missCount: 46,
),
// 100.0%.
"package:front_end/src/source/diet_parser.dart": (
hitCount: 4,
missCount: 0,
),
- // 93.19148936170212%.
+ // 93.99141630901288%.
"package:front_end/src/source/name_scheme.dart": (
hitCount: 219,
- missCount: 16,
+ missCount: 14,
),
// 95.16129032258065%.
"package:front_end/src/source/offset_map.dart": (
@@ -773,20 +763,20 @@
hitCount: 1213,
missCount: 197,
),
- // 92.65658747300216%.
+ // 93.058568329718%.
"package:front_end/src/source/source_constructor_builder.dart": (
hitCount: 858,
- missCount: 68,
+ missCount: 64,
),
// 95.73560767590618%.
"package:front_end/src/source/source_enum_builder.dart": (
hitCount: 449,
missCount: 20,
),
- // 61.261261261261254%.
+ // 64.15094339622641%.
"package:front_end/src/source/source_extension_builder.dart": (
hitCount: 68,
- missCount: 43,
+ missCount: 38,
),
// 84.32539682539682%.
"package:front_end/src/source/source_extension_type_declaration_builder.dart":
@@ -799,30 +789,30 @@
hitCount: 581,
missCount: 49,
),
- // 89.94668697638994%.
+ // 94.2537909018356%.
"package:front_end/src/source/source_field_builder.dart": (
hitCount: 1181,
- missCount: 132,
+ missCount: 72,
),
// 89.39393939393939%.
"package:front_end/src/source/source_function_builder.dart": (
hitCount: 295,
missCount: 35,
),
- // 85.35513790578472%.
+ // 85.2467024914509%.
"package:front_end/src/source/source_library_builder.dart": (
- hitCount: 3497,
- missCount: 600,
+ hitCount: 3490,
+ missCount: 604,
),
// 81.8988464951198%.
"package:front_end/src/source/source_loader.dart": (
hitCount: 1846,
missCount: 408,
),
- // 40.32258064516129%.
+ // 50.0%.
"package:front_end/src/source/source_member_builder.dart": (
hitCount: 25,
- missCount: 37,
+ missCount: 25,
),
// 96.11829944547135%.
"package:front_end/src/source/source_procedure_builder.dart": (
@@ -864,15 +854,15 @@
hitCount: 120,
missCount: 39,
),
- // 85.12820512820512%.
+ // 87.36842105263159%.
"package:front_end/src/type_inference/inference_results.dart": (
hitCount: 166,
- missCount: 29,
+ missCount: 24,
),
- // 90.37792719684674%.
+ // 90.44083526682135%.
"package:front_end/src/type_inference/inference_visitor.dart": (
hitCount: 7796,
- missCount: 830,
+ missCount: 824,
),
// 85.96491228070175%.
"package:front_end/src/type_inference/inference_visitor_base.dart": (
@@ -889,10 +879,10 @@
hitCount: 519,
missCount: 10,
),
- // 77.63578274760383%.
+ // 81.13522537562604%.
"package:front_end/src/type_inference/object_access_target.dart": (
hitCount: 486,
- missCount: 140,
+ missCount: 113,
),
// 98.0%.
"package:front_end/src/type_inference/shared_type_analyzer.dart": (
@@ -914,20 +904,20 @@
hitCount: 19,
missCount: 1,
),
- // 89.62962962962962%.
+ // 90.29850746268657%.
"package:front_end/src/type_inference/type_inference_engine.dart": (
hitCount: 484,
- missCount: 56,
+ missCount: 52,
),
// 54.037267080745345%.
"package:front_end/src/type_inference/type_inferrer.dart": (
hitCount: 87,
missCount: 74,
),
- // 36.666666666666664%.
+ // 42.30769230769231%.
"package:front_end/src/type_inference/type_schema.dart": (
hitCount: 11,
- missCount: 19,
+ missCount: 15,
),
// 88.88888888888889%.
"package:front_end/src/type_inference/type_schema_elimination.dart": (
@@ -954,15 +944,10 @@
hitCount: 20,
missCount: 18,
),
- // 5.5954088952654235%.
+ // 5.611510791366906%.
"package:front_end/src/util/parser_ast.dart": (
hitCount: 78,
- missCount: 1316,
- ),
- // 20.385501780850618%.
- "package:front_end/src/util/parser_ast_helper.dart": (
- hitCount: 973,
- missCount: 3800,
+ missCount: 1312,
),
// 86.54205607476636%.
"package:front_end/src/util/textual_outline.dart": (
diff --git a/pkg/front_end/test/run_all_coverage.dart b/pkg/front_end/test/run_all_coverage.dart
index e955659..5dea1b2 100644
--- a/pkg/front_end/test/run_all_coverage.dart
+++ b/pkg/front_end/test/run_all_coverage.dart
@@ -116,5 +116,7 @@
repoDirUri.resolve(".dart_tool/package_config.json"),
coverageTmpDir.uri,
silent: false,
+ extraCoverageIgnores: const [],
+ extraCoverageBlockIgnores: const [],
);
}
diff --git a/pkg/front_end/test/spell_checking_list_tests.txt b/pkg/front_end/test/spell_checking_list_tests.txt
index 99c03ad..5d8edc6 100644
--- a/pkg/front_end/test/spell_checking_list_tests.txt
+++ b/pkg/front_end/test/spell_checking_list_tests.txt
@@ -50,6 +50,7 @@
area
arglebargle
arr
+arrive
asdf
asserter
assure
@@ -613,6 +614,7 @@
prerequisite
press
pretends
+prettier
preventing
primitives
printouts
@@ -668,6 +670,7 @@
reorder
reordering
repaint
+replaceable
representative
repro
reproduce
@@ -791,6 +794,7 @@
te
templates
theoretically
+there'll
thereby
thereof
thread
@@ -834,6 +838,7 @@
uncompiled
unconverted
uncover
+uncovered
uncovers
underline
undocumented
diff --git a/pkg/front_end/testcases/general/constants/various.dart b/pkg/front_end/testcases/general/constants/various.dart
index bd7c03e..43f79de 100644
--- a/pkg/front_end/testcases/general/constants/various.dart
+++ b/pkg/front_end/testcases/general/constants/various.dart
@@ -111,6 +111,16 @@
this.y = "hello".length;
}
+class FooWithHashCodeField {
+ final int x;
+ final int y;
+ final int hashCode;
+ const FooWithHashCodeField(int x)
+ : this.x = x,
+ this.y = "hello".length,
+ this.hashCode = x * 42;
+}
+
class ExtendsFoo1 extends Foo {
// No constructor.
}
@@ -127,6 +137,12 @@
const Foo foo2 = const Foo(42);
const bool foosIdentical = identical(foo1, foo2);
const bool foosEqual = foo1 == foo2;
+
+const FooWithHashCodeField fooWithHashCodeField1 = const FooWithHashCodeField(42);
+const FooWithHashCodeField fooWithHashCodeField2 = const FooWithHashCodeField(42);
+const bool fooWithHashCodeFieldIdentical = identical(fooWithHashCodeField1, fooWithHashCodeField2);
+const bool fooWithHashCodeFieldEqual = fooWithHashCodeField1 == fooWithHashCodeField2;
+
const Symbol barFoo = const Symbol("Foo");
const Symbol barFooEqual = const Symbol("Foo=");
const Symbol tripleShiftSymbol = const Symbol(">>>");
diff --git a/pkg/front_end/testcases/general/constants/various.dart.strong.expect b/pkg/front_end/testcases/general/constants/various.dart.strong.expect
index 8e88044..01d5b41 100644
--- a/pkg/front_end/testcases/general/constants/various.dart.strong.expect
+++ b/pkg/front_end/testcases/general/constants/various.dart.strong.expect
@@ -2,7 +2,7 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/general/constants/various.dart:162:3: Error: A const constructor can't have a body.
+// pkg/front_end/testcases/general/constants/various.dart:178:3: Error: A const constructor can't have a body.
// Try removing either the 'const' keyword or the body.
// const ClassWithNonEmptyConstConstructor() {
// ^^^^^
@@ -39,11 +39,11 @@
// const y4 = y++;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:140:24: Error: Not a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:156:24: Error: Not a constant expression.
// const function_const = () {};
// ^^
//
-// pkg/front_end/testcases/general/constants/various.dart:180:14: Error: Can't access 'this' in a field initializer to read 'y'.
+// pkg/front_end/testcases/general/constants/various.dart:196:14: Error: Can't access 'this' in a field initializer to read 'y'.
// final z1 = y;
// ^
//
@@ -71,20 +71,20 @@
// @AbstractClassWithConstructor()
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:118:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// pkg/front_end/testcases/general/constants/various.dart:128:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
// Try using a constructor or factory that is 'const'.
// const ExtendsFoo1 extendsFoo1 = const ExtendsFoo1();
// ^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:121:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+// pkg/front_end/testcases/general/constants/various.dart:131:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
// const ExtendsFoo2();
// ^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:180:14: Error: Not a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:196:14: Error: Not a constant expression.
// final z1 = y;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:181:14: Error: Not a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:197:14: Error: Not a constant expression.
// final z2 = x;
// ^
//
@@ -92,7 +92,7 @@
// const AbstractClassWithConstructor();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:168:7: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// pkg/front_end/testcases/general/constants/various.dart:184:7: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
// Try using a constructor or factory that is 'const'.
// const ClassWithNonEmptyConstConstructor();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -107,7 +107,7 @@
// Object bar;
// ^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:114:7: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+// pkg/front_end/testcases/general/constants/various.dart:124:7: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
// class ExtendsFoo1 extends Foo {
// ^
//
@@ -181,37 +181,48 @@
// const x4 = x++;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:135:26: Error: Constant evaluation error:
+// pkg/front_end/testcases/general/constants/various.dart:144:62: Error: Constant evaluation error:
+// const bool fooWithHashCodeFieldEqual = fooWithHashCodeField1 == fooWithHashCodeField2;
+// ^
+// pkg/front_end/testcases/general/constants/various.dart:144:62: Context: Binary operator '==' requires receiver constant 'FooWithHashCodeField {x: 42, y: 5, hashCode: 1764}' of a type with primitive equality or type 'double', but was of type 'FooWithHashCodeField'.
+// - 'FooWithHashCodeField' is from 'pkg/front_end/testcases/general/constants/various.dart'.
+// const bool fooWithHashCodeFieldEqual = fooWithHashCodeField1 == fooWithHashCodeField2;
+// ^
+// pkg/front_end/testcases/general/constants/various.dart:144:12: Context: While analyzing:
+// const bool fooWithHashCodeFieldEqual = fooWithHashCodeField1 == fooWithHashCodeField2;
+// ^
+//
+// pkg/front_end/testcases/general/constants/various.dart:151:26: Error: Constant evaluation error:
// const int circularity1 = circularity2;
// ^
-// pkg/front_end/testcases/general/constants/various.dart:135:26: Context: Constant expression depends on itself.
+// pkg/front_end/testcases/general/constants/various.dart:151:26: Context: Constant expression depends on itself.
// const int circularity1 = circularity2;
// ^
-// pkg/front_end/testcases/general/constants/various.dart:135:11: Context: While analyzing:
+// pkg/front_end/testcases/general/constants/various.dart:151:11: Context: While analyzing:
// const int circularity1 = circularity2;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:148:7: Error: Constant evaluation error:
+// pkg/front_end/testcases/general/constants/various.dart:164:7: Error: Constant evaluation error:
// const ConstClassWithFailingAssertWithEmptyMessage();
// ^
-// pkg/front_end/testcases/general/constants/various.dart:144:64: Context: This assertion failed with message: (empty)
+// pkg/front_end/testcases/general/constants/various.dart:160:64: Context: This assertion failed with message: (empty)
// const ConstClassWithFailingAssertWithEmptyMessage() : assert(false, "");
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:185:7: Error: Constant evaluation error:
+// pkg/front_end/testcases/general/constants/various.dart:201:7: Error: Constant evaluation error:
// const ConstClassWithFinalFields2();
// ^
-// pkg/front_end/testcases/general/constants/various.dart:181:14: Context: The invocation of 'x' is not allowed in a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:197:14: Context: The invocation of 'x' is not allowed in a constant expression.
// final z2 = x;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:203:35: Error: Constant evaluation error:
+// pkg/front_end/testcases/general/constants/various.dart:219:35: Error: Constant evaluation error:
// const bool.fromEnvironment("foo") ? id1 : willBecomeNull;
// ^
-// pkg/front_end/testcases/general/constants/various.dart:203:35: Context: Expected constant 'null' to be of type 'int Function(int)', but was of type 'Null'.
+// pkg/front_end/testcases/general/constants/various.dart:219:35: Context: Expected constant 'null' to be of type 'int Function(int)', but was of type 'Null'.
// const bool.fromEnvironment("foo") ? id1 : willBecomeNull;
// ^
-// pkg/front_end/testcases/general/constants/various.dart:202:25: Context: While analyzing:
+// pkg/front_end/testcases/general/constants/various.dart:218:25: Context: While analyzing:
// const int Function(int) willBecomeNullToo =
// ^
//
@@ -246,6 +257,14 @@
: self::Foo::x = x, self::Foo::y = "hello".{core::String::length}{core::int}, super core::Object::•()
;
}
+class FooWithHashCodeField extends core::Object /*hasConstConstructor*/ {
+ final field core::int x;
+ final field core::int y;
+ final field core::int hashCode;
+ const constructor •(core::int x) → self::FooWithHashCodeField
+ : self::FooWithHashCodeField::x = x, self::FooWithHashCodeField::y = "hello".{core::String::length}{core::int}, self::FooWithHashCodeField::hashCode = x.{core::num::*}(42){(core::num) → core::int}, super core::Object::•()
+ ;
+}
class ExtendsFoo1 extends self::Foo {
synthetic constructor •() → self::ExtendsFoo1
: invalid-initializer
@@ -253,7 +272,7 @@
}
class ExtendsFoo2 extends self::Foo /*hasConstConstructor*/ {
const constructor •() → self::ExtendsFoo2
- : final dynamic #t1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:121:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+ : final dynamic #t1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:131:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
const ExtendsFoo2();
^^^^^^^^^^^"
;
@@ -392,34 +411,39 @@
const y4 = y++;
^";
static field self::AbstractClassWithConstructor abstractClassWithConstructor = invalid-expression "The class 'AbstractClassWithConstructor' is abstract and can't be instantiated.";
-static const field self::ExtendsFoo1 extendsFoo1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:118:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+static const field self::ExtendsFoo1 extendsFoo1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:128:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
Try using a constructor or factory that is 'const'.
const ExtendsFoo1 extendsFoo1 = const ExtendsFoo1();
^^^^^^^^^^^";
-static const field self::ExtendsFoo2 extendsFoo2 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:121:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+static const field self::ExtendsFoo2 extendsFoo2 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:131:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
const ExtendsFoo2();
^^^^^^^^^^^";
static const field self::Foo foo1 = #C13;
static const field self::Foo foo2 = #C13;
static const field core::bool foosIdentical = #C2;
static const field core::bool foosEqual = #C2;
-static const field core::Symbol barFoo = #C14;
-static const field core::Symbol barFooEqual = #C15;
-static const field core::Symbol tripleShiftSymbol = #C16;
-static const field core::Symbol symbolWithDots = #C17;
+static const field self::FooWithHashCodeField fooWithHashCodeField1 = #C15;
+static const field self::FooWithHashCodeField fooWithHashCodeField2 = #C15;
+static const field core::bool fooWithHashCodeFieldIdentical = #C2;
+static const field core::bool fooWithHashCodeFieldEqual = invalid-expression "Binary operator '==' requires receiver constant 'FooWithHashCodeField {x: 42, y: 5, hashCode: 1764}' of a type with primitive equality or type 'double', but was of type 'FooWithHashCodeField'.
+ - 'FooWithHashCodeField' is from 'pkg/front_end/testcases/general/constants/various.dart'.";
+static const field core::Symbol barFoo = #C16;
+static const field core::Symbol barFooEqual = #C17;
+static const field core::Symbol tripleShiftSymbol = #C18;
+static const field core::Symbol symbolWithDots = #C19;
static const field core::int circularity1 = invalid-expression "Constant expression depends on itself.";
static const field core::int circularity2 = invalid-expression "Constant expression depends on itself.";
static const field core::int circularity3 = invalid-expression "Constant expression depends on itself.";
static const field core::int circularity4 = invalid-expression "Constant expression depends on itself.";
-static const field invalid-type function_const = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:140:24: Error: Not a constant expression.
+static const field invalid-type function_const = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:156:24: Error: Not a constant expression.
const function_const = () {};
^^";
static field () → Null function_var = () → Null {};
static field self::ConstClassWithFailingAssertWithEmptyMessage failedAssertEmptyMessage = invalid-expression "This assertion failed with message: (empty)";
-static const field self::ClassWithTypeArguments<dynamic, dynamic, dynamic> classWithTypeArguments1 = #C18;
-static const field self::ClassWithTypeArguments<dynamic, dynamic, dynamic> classWithTypeArguments2 = #C19;
+static const field self::ClassWithTypeArguments<dynamic, dynamic, dynamic> classWithTypeArguments1 = #C20;
+static const field self::ClassWithTypeArguments<dynamic, dynamic, dynamic> classWithTypeArguments2 = #C21;
static const field core::bool classWithTypeArgumentsIdentical = #C1;
-static field self::ClassWithNonEmptyConstConstructor classWithNonEmptyConstConstructor = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:168:7: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+static field self::ClassWithNonEmptyConstConstructor classWithNonEmptyConstConstructor = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:184:7: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
Try using a constructor or factory that is 'const'.
const ClassWithNonEmptyConstConstructor();
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^";
@@ -432,16 +456,16 @@
static const field core::bool zeroPointZeroEqualToZero = #C2;
static const field core::bool zeroEqualToZeroPointZero = #C2;
static const field core::bool nanEqual = #C1;
-static const field dynamic willBecomeNull = #C20;
+static const field dynamic willBecomeNull = #C22;
static const field (core::int) → core::int willBecomeNullToo = invalid-expression "Expected constant 'null' to be of type 'int Function(int)', but was of type 'Null'.";
-static const field (core::int) → core::int partialInstantiation = #C22;
+static const field (core::int) → core::int partialInstantiation = #C24;
static const field core::bool yBool = #C2;
static const field core::bool zBool = #C1;
static const field core::Object maybeInt = #C2;
static const field core::bool isItInt = #C1;
static const field core::Object maybeInt2 = #C2;
static const field core::bool isItInt2 = #C1;
-static const field core::int? maybeInt3 = #C20;
+static const field core::int? maybeInt3 = #C22;
static const field core::bool isItInt3 = #C1;
static method id1<T extends core::Object? = dynamic>(self::id1::T% t) → self::id1::T%
return t;
@@ -466,23 +490,26 @@
#C11 = 1
#C12 = 5
#C13 = self::Foo {x:#C6, y:#C12}
- #C14 = #Foo
- #C15 = #Foo=
- #C16 = #>>>
- #C17 = #I.Have.Dots
- #C18 = self::ClassWithTypeArguments<core::int, core::int, core::int> {}
- #C19 = self::ClassWithTypeArguments<dynamic, dynamic, dynamic> {}
- #C20 = null
- #C21 = static-tearoff self::id1
- #C22 = instantiation #C21 <core::int>
+ #C14 = 1764
+ #C15 = self::FooWithHashCodeField {x:#C6, y:#C12, hashCode:#C14}
+ #C16 = #Foo
+ #C17 = #Foo=
+ #C18 = #>>>
+ #C19 = #I.Have.Dots
+ #C20 = self::ClassWithTypeArguments<core::int, core::int, core::int> {}
+ #C21 = self::ClassWithTypeArguments<dynamic, dynamic, dynamic> {}
+ #C22 = null
+ #C23 = static-tearoff self::id1
+ #C24 = instantiation #C23 <core::int>
}
Constructor coverage from constants:
org-dartlang-testcase:///various.dart:
-- ExtendsFoo2. (from org-dartlang-testcase:///various.dart:121:9)
+- ExtendsFoo2. (from org-dartlang-testcase:///various.dart:131:9)
- Foo. (from org-dartlang-testcase:///various.dart:109:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
-- ConstClassWithFailingAssertWithEmptyMessage. (from org-dartlang-testcase:///various.dart:144:9)
-- ClassWithTypeArguments. (from org-dartlang-testcase:///various.dart:151:9)
-- ConstClassWithFinalFields2. (from org-dartlang-testcase:///various.dart:177:9)
+- FooWithHashCodeField. (from org-dartlang-testcase:///various.dart:118:9)
+- ConstClassWithFailingAssertWithEmptyMessage. (from org-dartlang-testcase:///various.dart:160:9)
+- ClassWithTypeArguments. (from org-dartlang-testcase:///various.dart:167:9)
+- ConstClassWithFinalFields2. (from org-dartlang-testcase:///various.dart:193:9)
diff --git a/pkg/front_end/testcases/general/constants/various.dart.strong.modular.expect b/pkg/front_end/testcases/general/constants/various.dart.strong.modular.expect
index 8e88044..01d5b41 100644
--- a/pkg/front_end/testcases/general/constants/various.dart.strong.modular.expect
+++ b/pkg/front_end/testcases/general/constants/various.dart.strong.modular.expect
@@ -2,7 +2,7 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/general/constants/various.dart:162:3: Error: A const constructor can't have a body.
+// pkg/front_end/testcases/general/constants/various.dart:178:3: Error: A const constructor can't have a body.
// Try removing either the 'const' keyword or the body.
// const ClassWithNonEmptyConstConstructor() {
// ^^^^^
@@ -39,11 +39,11 @@
// const y4 = y++;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:140:24: Error: Not a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:156:24: Error: Not a constant expression.
// const function_const = () {};
// ^^
//
-// pkg/front_end/testcases/general/constants/various.dart:180:14: Error: Can't access 'this' in a field initializer to read 'y'.
+// pkg/front_end/testcases/general/constants/various.dart:196:14: Error: Can't access 'this' in a field initializer to read 'y'.
// final z1 = y;
// ^
//
@@ -71,20 +71,20 @@
// @AbstractClassWithConstructor()
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:118:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// pkg/front_end/testcases/general/constants/various.dart:128:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
// Try using a constructor or factory that is 'const'.
// const ExtendsFoo1 extendsFoo1 = const ExtendsFoo1();
// ^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:121:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+// pkg/front_end/testcases/general/constants/various.dart:131:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
// const ExtendsFoo2();
// ^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:180:14: Error: Not a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:196:14: Error: Not a constant expression.
// final z1 = y;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:181:14: Error: Not a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:197:14: Error: Not a constant expression.
// final z2 = x;
// ^
//
@@ -92,7 +92,7 @@
// const AbstractClassWithConstructor();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:168:7: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// pkg/front_end/testcases/general/constants/various.dart:184:7: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
// Try using a constructor or factory that is 'const'.
// const ClassWithNonEmptyConstConstructor();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -107,7 +107,7 @@
// Object bar;
// ^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:114:7: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+// pkg/front_end/testcases/general/constants/various.dart:124:7: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
// class ExtendsFoo1 extends Foo {
// ^
//
@@ -181,37 +181,48 @@
// const x4 = x++;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:135:26: Error: Constant evaluation error:
+// pkg/front_end/testcases/general/constants/various.dart:144:62: Error: Constant evaluation error:
+// const bool fooWithHashCodeFieldEqual = fooWithHashCodeField1 == fooWithHashCodeField2;
+// ^
+// pkg/front_end/testcases/general/constants/various.dart:144:62: Context: Binary operator '==' requires receiver constant 'FooWithHashCodeField {x: 42, y: 5, hashCode: 1764}' of a type with primitive equality or type 'double', but was of type 'FooWithHashCodeField'.
+// - 'FooWithHashCodeField' is from 'pkg/front_end/testcases/general/constants/various.dart'.
+// const bool fooWithHashCodeFieldEqual = fooWithHashCodeField1 == fooWithHashCodeField2;
+// ^
+// pkg/front_end/testcases/general/constants/various.dart:144:12: Context: While analyzing:
+// const bool fooWithHashCodeFieldEqual = fooWithHashCodeField1 == fooWithHashCodeField2;
+// ^
+//
+// pkg/front_end/testcases/general/constants/various.dart:151:26: Error: Constant evaluation error:
// const int circularity1 = circularity2;
// ^
-// pkg/front_end/testcases/general/constants/various.dart:135:26: Context: Constant expression depends on itself.
+// pkg/front_end/testcases/general/constants/various.dart:151:26: Context: Constant expression depends on itself.
// const int circularity1 = circularity2;
// ^
-// pkg/front_end/testcases/general/constants/various.dart:135:11: Context: While analyzing:
+// pkg/front_end/testcases/general/constants/various.dart:151:11: Context: While analyzing:
// const int circularity1 = circularity2;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:148:7: Error: Constant evaluation error:
+// pkg/front_end/testcases/general/constants/various.dart:164:7: Error: Constant evaluation error:
// const ConstClassWithFailingAssertWithEmptyMessage();
// ^
-// pkg/front_end/testcases/general/constants/various.dart:144:64: Context: This assertion failed with message: (empty)
+// pkg/front_end/testcases/general/constants/various.dart:160:64: Context: This assertion failed with message: (empty)
// const ConstClassWithFailingAssertWithEmptyMessage() : assert(false, "");
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:185:7: Error: Constant evaluation error:
+// pkg/front_end/testcases/general/constants/various.dart:201:7: Error: Constant evaluation error:
// const ConstClassWithFinalFields2();
// ^
-// pkg/front_end/testcases/general/constants/various.dart:181:14: Context: The invocation of 'x' is not allowed in a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:197:14: Context: The invocation of 'x' is not allowed in a constant expression.
// final z2 = x;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:203:35: Error: Constant evaluation error:
+// pkg/front_end/testcases/general/constants/various.dart:219:35: Error: Constant evaluation error:
// const bool.fromEnvironment("foo") ? id1 : willBecomeNull;
// ^
-// pkg/front_end/testcases/general/constants/various.dart:203:35: Context: Expected constant 'null' to be of type 'int Function(int)', but was of type 'Null'.
+// pkg/front_end/testcases/general/constants/various.dart:219:35: Context: Expected constant 'null' to be of type 'int Function(int)', but was of type 'Null'.
// const bool.fromEnvironment("foo") ? id1 : willBecomeNull;
// ^
-// pkg/front_end/testcases/general/constants/various.dart:202:25: Context: While analyzing:
+// pkg/front_end/testcases/general/constants/various.dart:218:25: Context: While analyzing:
// const int Function(int) willBecomeNullToo =
// ^
//
@@ -246,6 +257,14 @@
: self::Foo::x = x, self::Foo::y = "hello".{core::String::length}{core::int}, super core::Object::•()
;
}
+class FooWithHashCodeField extends core::Object /*hasConstConstructor*/ {
+ final field core::int x;
+ final field core::int y;
+ final field core::int hashCode;
+ const constructor •(core::int x) → self::FooWithHashCodeField
+ : self::FooWithHashCodeField::x = x, self::FooWithHashCodeField::y = "hello".{core::String::length}{core::int}, self::FooWithHashCodeField::hashCode = x.{core::num::*}(42){(core::num) → core::int}, super core::Object::•()
+ ;
+}
class ExtendsFoo1 extends self::Foo {
synthetic constructor •() → self::ExtendsFoo1
: invalid-initializer
@@ -253,7 +272,7 @@
}
class ExtendsFoo2 extends self::Foo /*hasConstConstructor*/ {
const constructor •() → self::ExtendsFoo2
- : final dynamic #t1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:121:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+ : final dynamic #t1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:131:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
const ExtendsFoo2();
^^^^^^^^^^^"
;
@@ -392,34 +411,39 @@
const y4 = y++;
^";
static field self::AbstractClassWithConstructor abstractClassWithConstructor = invalid-expression "The class 'AbstractClassWithConstructor' is abstract and can't be instantiated.";
-static const field self::ExtendsFoo1 extendsFoo1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:118:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+static const field self::ExtendsFoo1 extendsFoo1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:128:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
Try using a constructor or factory that is 'const'.
const ExtendsFoo1 extendsFoo1 = const ExtendsFoo1();
^^^^^^^^^^^";
-static const field self::ExtendsFoo2 extendsFoo2 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:121:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+static const field self::ExtendsFoo2 extendsFoo2 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:131:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
const ExtendsFoo2();
^^^^^^^^^^^";
static const field self::Foo foo1 = #C13;
static const field self::Foo foo2 = #C13;
static const field core::bool foosIdentical = #C2;
static const field core::bool foosEqual = #C2;
-static const field core::Symbol barFoo = #C14;
-static const field core::Symbol barFooEqual = #C15;
-static const field core::Symbol tripleShiftSymbol = #C16;
-static const field core::Symbol symbolWithDots = #C17;
+static const field self::FooWithHashCodeField fooWithHashCodeField1 = #C15;
+static const field self::FooWithHashCodeField fooWithHashCodeField2 = #C15;
+static const field core::bool fooWithHashCodeFieldIdentical = #C2;
+static const field core::bool fooWithHashCodeFieldEqual = invalid-expression "Binary operator '==' requires receiver constant 'FooWithHashCodeField {x: 42, y: 5, hashCode: 1764}' of a type with primitive equality or type 'double', but was of type 'FooWithHashCodeField'.
+ - 'FooWithHashCodeField' is from 'pkg/front_end/testcases/general/constants/various.dart'.";
+static const field core::Symbol barFoo = #C16;
+static const field core::Symbol barFooEqual = #C17;
+static const field core::Symbol tripleShiftSymbol = #C18;
+static const field core::Symbol symbolWithDots = #C19;
static const field core::int circularity1 = invalid-expression "Constant expression depends on itself.";
static const field core::int circularity2 = invalid-expression "Constant expression depends on itself.";
static const field core::int circularity3 = invalid-expression "Constant expression depends on itself.";
static const field core::int circularity4 = invalid-expression "Constant expression depends on itself.";
-static const field invalid-type function_const = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:140:24: Error: Not a constant expression.
+static const field invalid-type function_const = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:156:24: Error: Not a constant expression.
const function_const = () {};
^^";
static field () → Null function_var = () → Null {};
static field self::ConstClassWithFailingAssertWithEmptyMessage failedAssertEmptyMessage = invalid-expression "This assertion failed with message: (empty)";
-static const field self::ClassWithTypeArguments<dynamic, dynamic, dynamic> classWithTypeArguments1 = #C18;
-static const field self::ClassWithTypeArguments<dynamic, dynamic, dynamic> classWithTypeArguments2 = #C19;
+static const field self::ClassWithTypeArguments<dynamic, dynamic, dynamic> classWithTypeArguments1 = #C20;
+static const field self::ClassWithTypeArguments<dynamic, dynamic, dynamic> classWithTypeArguments2 = #C21;
static const field core::bool classWithTypeArgumentsIdentical = #C1;
-static field self::ClassWithNonEmptyConstConstructor classWithNonEmptyConstConstructor = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:168:7: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+static field self::ClassWithNonEmptyConstConstructor classWithNonEmptyConstConstructor = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:184:7: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
Try using a constructor or factory that is 'const'.
const ClassWithNonEmptyConstConstructor();
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^";
@@ -432,16 +456,16 @@
static const field core::bool zeroPointZeroEqualToZero = #C2;
static const field core::bool zeroEqualToZeroPointZero = #C2;
static const field core::bool nanEqual = #C1;
-static const field dynamic willBecomeNull = #C20;
+static const field dynamic willBecomeNull = #C22;
static const field (core::int) → core::int willBecomeNullToo = invalid-expression "Expected constant 'null' to be of type 'int Function(int)', but was of type 'Null'.";
-static const field (core::int) → core::int partialInstantiation = #C22;
+static const field (core::int) → core::int partialInstantiation = #C24;
static const field core::bool yBool = #C2;
static const field core::bool zBool = #C1;
static const field core::Object maybeInt = #C2;
static const field core::bool isItInt = #C1;
static const field core::Object maybeInt2 = #C2;
static const field core::bool isItInt2 = #C1;
-static const field core::int? maybeInt3 = #C20;
+static const field core::int? maybeInt3 = #C22;
static const field core::bool isItInt3 = #C1;
static method id1<T extends core::Object? = dynamic>(self::id1::T% t) → self::id1::T%
return t;
@@ -466,23 +490,26 @@
#C11 = 1
#C12 = 5
#C13 = self::Foo {x:#C6, y:#C12}
- #C14 = #Foo
- #C15 = #Foo=
- #C16 = #>>>
- #C17 = #I.Have.Dots
- #C18 = self::ClassWithTypeArguments<core::int, core::int, core::int> {}
- #C19 = self::ClassWithTypeArguments<dynamic, dynamic, dynamic> {}
- #C20 = null
- #C21 = static-tearoff self::id1
- #C22 = instantiation #C21 <core::int>
+ #C14 = 1764
+ #C15 = self::FooWithHashCodeField {x:#C6, y:#C12, hashCode:#C14}
+ #C16 = #Foo
+ #C17 = #Foo=
+ #C18 = #>>>
+ #C19 = #I.Have.Dots
+ #C20 = self::ClassWithTypeArguments<core::int, core::int, core::int> {}
+ #C21 = self::ClassWithTypeArguments<dynamic, dynamic, dynamic> {}
+ #C22 = null
+ #C23 = static-tearoff self::id1
+ #C24 = instantiation #C23 <core::int>
}
Constructor coverage from constants:
org-dartlang-testcase:///various.dart:
-- ExtendsFoo2. (from org-dartlang-testcase:///various.dart:121:9)
+- ExtendsFoo2. (from org-dartlang-testcase:///various.dart:131:9)
- Foo. (from org-dartlang-testcase:///various.dart:109:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
-- ConstClassWithFailingAssertWithEmptyMessage. (from org-dartlang-testcase:///various.dart:144:9)
-- ClassWithTypeArguments. (from org-dartlang-testcase:///various.dart:151:9)
-- ConstClassWithFinalFields2. (from org-dartlang-testcase:///various.dart:177:9)
+- FooWithHashCodeField. (from org-dartlang-testcase:///various.dart:118:9)
+- ConstClassWithFailingAssertWithEmptyMessage. (from org-dartlang-testcase:///various.dart:160:9)
+- ClassWithTypeArguments. (from org-dartlang-testcase:///various.dart:167:9)
+- ConstClassWithFinalFields2. (from org-dartlang-testcase:///various.dart:193:9)
diff --git a/pkg/front_end/testcases/general/constants/various.dart.strong.outline.expect b/pkg/front_end/testcases/general/constants/various.dart.strong.outline.expect
index ab0bb85..0d65ced 100644
--- a/pkg/front_end/testcases/general/constants/various.dart.strong.outline.expect
+++ b/pkg/front_end/testcases/general/constants/various.dart.strong.outline.expect
@@ -2,7 +2,7 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/general/constants/various.dart:162:3: Error: A const constructor can't have a body.
+// pkg/front_end/testcases/general/constants/various.dart:178:3: Error: A const constructor can't have a body.
// Try removing either the 'const' keyword or the body.
// const ClassWithNonEmptyConstConstructor() {
// ^^^^^
@@ -39,11 +39,11 @@
// const y4 = y++;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:140:24: Error: Not a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:156:24: Error: Not a constant expression.
// const function_const = () {};
// ^^
//
-// pkg/front_end/testcases/general/constants/various.dart:180:14: Error: Can't access 'this' in a field initializer to read 'y'.
+// pkg/front_end/testcases/general/constants/various.dart:196:14: Error: Can't access 'this' in a field initializer to read 'y'.
// final z1 = y;
// ^
//
@@ -71,20 +71,20 @@
// @AbstractClassWithConstructor()
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:118:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// pkg/front_end/testcases/general/constants/various.dart:128:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
// Try using a constructor or factory that is 'const'.
// const ExtendsFoo1 extendsFoo1 = const ExtendsFoo1();
// ^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:121:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+// pkg/front_end/testcases/general/constants/various.dart:131:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
// const ExtendsFoo2();
// ^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:180:14: Error: Not a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:196:14: Error: Not a constant expression.
// final z1 = y;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:181:14: Error: Not a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:197:14: Error: Not a constant expression.
// final z2 = x;
// ^
//
@@ -117,13 +117,21 @@
: self::Foo::x = x, self::Foo::y = "hello".{core::String::length}{core::int}, super core::Object::•()
;
}
+class FooWithHashCodeField extends core::Object /*hasConstConstructor*/ {
+ final field core::int x;
+ final field core::int y;
+ final field core::int hashCode;
+ const constructor •(core::int x) → self::FooWithHashCodeField
+ : self::FooWithHashCodeField::x = x, self::FooWithHashCodeField::y = "hello".{core::String::length}{core::int}, self::FooWithHashCodeField::hashCode = x.{core::num::*}(42){(core::num) → core::int}, super core::Object::•()
+ ;
+}
class ExtendsFoo1 extends self::Foo {
synthetic constructor •() → self::ExtendsFoo1
;
}
class ExtendsFoo2 extends self::Foo /*hasConstConstructor*/ {
const constructor •() → self::ExtendsFoo2
- : final dynamic #t1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:121:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+ : final dynamic #t1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:131:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
const ExtendsFoo2();
^^^^^^^^^^^"
;
@@ -232,7 +240,7 @@
const y4 = y++;
^" in #t10;
static field self::AbstractClassWithConstructor abstractClassWithConstructor;
-static const field self::ExtendsFoo1 extendsFoo1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:118:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+static const field self::ExtendsFoo1 extendsFoo1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:128:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
Try using a constructor or factory that is 'const'.
const ExtendsFoo1 extendsFoo1 = const ExtendsFoo1();
^^^^^^^^^^^";
@@ -241,6 +249,10 @@
static const field self::Foo foo2 = const self::Foo::•(42);
static const field core::bool foosIdentical = core::identical(self::foo1, self::foo2);
static const field core::bool foosEqual = self::foo1 =={core::Object::==}{(core::Object) → core::bool} self::foo2;
+static const field self::FooWithHashCodeField fooWithHashCodeField1 = const self::FooWithHashCodeField::•(42);
+static const field self::FooWithHashCodeField fooWithHashCodeField2 = const self::FooWithHashCodeField::•(42);
+static const field core::bool fooWithHashCodeFieldIdentical = core::identical(self::fooWithHashCodeField1, self::fooWithHashCodeField2);
+static const field core::bool fooWithHashCodeFieldEqual = self::fooWithHashCodeField1 =={core::Object::==}{(core::Object) → core::bool} self::fooWithHashCodeField2;
static const field core::Symbol barFoo = const _in::Symbol::•("Foo");
static const field core::Symbol barFooEqual = const _in::Symbol::•("Foo=");
static const field core::Symbol tripleShiftSymbol = const _in::Symbol::•(">>>");
@@ -249,7 +261,7 @@
static const field core::int circularity2 = self::circularity3;
static const field core::int circularity3 = self::circularity4;
static const field core::int circularity4 = self::circularity1;
-static const field invalid-type function_const = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:140:24: Error: Not a constant expression.
+static const field invalid-type function_const = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:156:24: Error: Not a constant expression.
const function_const = () {};
^^";
static field () → Null function_var;
@@ -288,6 +300,7 @@
Extra constant evaluation status:
Evaluated: InstanceGet @ org-dartlang-testcase:///various.dart:111:26 -> IntConstant(5)
+Evaluated: InstanceGet @ org-dartlang-testcase:///various.dart:120:26 -> IntConstant(5)
Evaluated: FactoryConstructorInvocation @ org-dartlang-testcase:///various.dart:6:31 -> BoolConstant(false)
Evaluated: FactoryConstructorInvocation @ org-dartlang-testcase:///various.dart:7:30 -> BoolConstant(false)
Evaluated: LogicalExpression @ org-dartlang-testcase:///various.dart:20:29 -> BoolConstant(true)
@@ -323,33 +336,38 @@
Evaluated: VariableGet @ org-dartlang-testcase:///various.dart:84:12 -> IntConstant(1)
Evaluated: StaticGet @ org-dartlang-testcase:///various.dart:85:12 -> IntConstant(1)
Evaluated: VariableGet @ org-dartlang-testcase:///various.dart:85:12 -> IntConstant(1)
-Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:126:24 -> InstanceConstant(const Foo{Foo.x: 42, Foo.y: 5})
-Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:127:24 -> InstanceConstant(const Foo{Foo.x: 42, Foo.y: 5})
-Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:128:28 -> BoolConstant(true)
-Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:129:29 -> BoolConstant(true)
-Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:130:29 -> SymbolConstant(#Foo)
-Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:131:34 -> SymbolConstant(#Foo=)
-Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:132:40 -> SymbolConstant(#>>>)
-Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:133:37 -> SymbolConstant(#I.Have.Dots)
-Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:155:7 -> InstanceConstant(const ClassWithTypeArguments<int, int, int>{})
-Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:157:7 -> InstanceConstant(const ClassWithTypeArguments<dynamic, dynamic, dynamic>{})
-Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:159:1 -> BoolConstant(false)
-Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:187:32 -> BoolConstant(true)
-Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:188:38 -> BoolConstant(false)
-Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:189:38 -> BoolConstant(false)
-Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:190:22 -> BoolConstant(true)
-Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:192:32 -> BoolConstant(true)
-Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:193:38 -> BoolConstant(true)
-Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:194:36 -> BoolConstant(true)
-Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:195:24 -> BoolConstant(false)
-Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:200:66 -> NullConstant(null)
-Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:203:35 -> NullConstant(null)
-Evaluated: AsExpression @ org-dartlang-testcase:///various.dart:205:35 -> InstantiationConstant(id1<int>)
-Evaluated: Not @ org-dartlang-testcase:///various.dart:208:20 -> BoolConstant(false)
-Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:210:46 -> BoolConstant(true)
-Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:211:38 -> BoolConstant(false)
-Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:212:25 -> BoolConstant(true)
-Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:213:40 -> BoolConstant(false)
-Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:214:25 -> NullConstant(null)
-Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:215:40 -> BoolConstant(false)
-Extra constant evaluation: evaluated: 146, effectively constant: 65
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:136:24 -> InstanceConstant(const Foo{Foo.x: 42, Foo.y: 5})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:137:24 -> InstanceConstant(const Foo{Foo.x: 42, Foo.y: 5})
+Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:138:28 -> BoolConstant(true)
+Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:139:29 -> BoolConstant(true)
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:141:58 -> InstanceConstant(const FooWithHashCodeField{FooWithHashCodeField.x: 42, FooWithHashCodeField.y: 5, FooWithHashCodeField.hashCode: 1764})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:142:58 -> InstanceConstant(const FooWithHashCodeField{FooWithHashCodeField.x: 42, FooWithHashCodeField.y: 5, FooWithHashCodeField.hashCode: 1764})
+Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:143:44 -> BoolConstant(true)
+Evaluated: StaticGet @ org-dartlang-testcase:///various.dart:144:40 -> InstanceConstant(const FooWithHashCodeField{FooWithHashCodeField.x: 42, FooWithHashCodeField.y: 5, FooWithHashCodeField.hashCode: 1764})
+Evaluated: StaticGet @ org-dartlang-testcase:///various.dart:144:65 -> InstanceConstant(const FooWithHashCodeField{FooWithHashCodeField.x: 42, FooWithHashCodeField.y: 5, FooWithHashCodeField.hashCode: 1764})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:146:29 -> SymbolConstant(#Foo)
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:147:34 -> SymbolConstant(#Foo=)
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:148:40 -> SymbolConstant(#>>>)
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:149:37 -> SymbolConstant(#I.Have.Dots)
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:171:7 -> InstanceConstant(const ClassWithTypeArguments<int, int, int>{})
+Evaluated: ConstructorInvocation @ org-dartlang-testcase:///various.dart:173:7 -> InstanceConstant(const ClassWithTypeArguments<dynamic, dynamic, dynamic>{})
+Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:175:1 -> BoolConstant(false)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:203:32 -> BoolConstant(true)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:204:38 -> BoolConstant(false)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:205:38 -> BoolConstant(false)
+Evaluated: StaticInvocation @ org-dartlang-testcase:///various.dart:206:22 -> BoolConstant(true)
+Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:208:32 -> BoolConstant(true)
+Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:209:38 -> BoolConstant(true)
+Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:210:36 -> BoolConstant(true)
+Evaluated: EqualsCall @ org-dartlang-testcase:///various.dart:211:24 -> BoolConstant(false)
+Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:216:66 -> NullConstant(null)
+Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:219:35 -> NullConstant(null)
+Evaluated: AsExpression @ org-dartlang-testcase:///various.dart:221:35 -> InstantiationConstant(id1<int>)
+Evaluated: Not @ org-dartlang-testcase:///various.dart:224:20 -> BoolConstant(false)
+Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:226:46 -> BoolConstant(true)
+Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:227:38 -> BoolConstant(false)
+Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:228:25 -> BoolConstant(true)
+Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:229:40 -> BoolConstant(false)
+Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:230:25 -> NullConstant(null)
+Evaluated: ConditionalExpression @ org-dartlang-testcase:///various.dart:231:40 -> BoolConstant(false)
+Extra constant evaluation: evaluated: 156, effectively constant: 71
diff --git a/pkg/front_end/testcases/general/constants/various.dart.strong.transformed.expect b/pkg/front_end/testcases/general/constants/various.dart.strong.transformed.expect
index 27cedb6..a869efc 100644
--- a/pkg/front_end/testcases/general/constants/various.dart.strong.transformed.expect
+++ b/pkg/front_end/testcases/general/constants/various.dart.strong.transformed.expect
@@ -2,7 +2,7 @@
//
// Problems in library:
//
-// pkg/front_end/testcases/general/constants/various.dart:162:3: Error: A const constructor can't have a body.
+// pkg/front_end/testcases/general/constants/various.dart:178:3: Error: A const constructor can't have a body.
// Try removing either the 'const' keyword or the body.
// const ClassWithNonEmptyConstConstructor() {
// ^^^^^
@@ -39,11 +39,11 @@
// const y4 = y++;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:140:24: Error: Not a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:156:24: Error: Not a constant expression.
// const function_const = () {};
// ^^
//
-// pkg/front_end/testcases/general/constants/various.dart:180:14: Error: Can't access 'this' in a field initializer to read 'y'.
+// pkg/front_end/testcases/general/constants/various.dart:196:14: Error: Can't access 'this' in a field initializer to read 'y'.
// final z1 = y;
// ^
//
@@ -71,20 +71,20 @@
// @AbstractClassWithConstructor()
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:118:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// pkg/front_end/testcases/general/constants/various.dart:128:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
// Try using a constructor or factory that is 'const'.
// const ExtendsFoo1 extendsFoo1 = const ExtendsFoo1();
// ^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:121:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+// pkg/front_end/testcases/general/constants/various.dart:131:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
// const ExtendsFoo2();
// ^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:180:14: Error: Not a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:196:14: Error: Not a constant expression.
// final z1 = y;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:181:14: Error: Not a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:197:14: Error: Not a constant expression.
// final z2 = x;
// ^
//
@@ -92,7 +92,7 @@
// const AbstractClassWithConstructor();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:168:7: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+// pkg/front_end/testcases/general/constants/various.dart:184:7: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
// Try using a constructor or factory that is 'const'.
// const ClassWithNonEmptyConstConstructor();
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -107,7 +107,7 @@
// Object bar;
// ^^^
//
-// pkg/front_end/testcases/general/constants/various.dart:114:7: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+// pkg/front_end/testcases/general/constants/various.dart:124:7: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
// class ExtendsFoo1 extends Foo {
// ^
//
@@ -181,37 +181,48 @@
// const x4 = x++;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:135:26: Error: Constant evaluation error:
+// pkg/front_end/testcases/general/constants/various.dart:144:62: Error: Constant evaluation error:
+// const bool fooWithHashCodeFieldEqual = fooWithHashCodeField1 == fooWithHashCodeField2;
+// ^
+// pkg/front_end/testcases/general/constants/various.dart:144:62: Context: Binary operator '==' requires receiver constant 'FooWithHashCodeField {x: 42, y: 5, hashCode: 1764}' of a type with primitive equality or type 'double', but was of type 'FooWithHashCodeField'.
+// - 'FooWithHashCodeField' is from 'pkg/front_end/testcases/general/constants/various.dart'.
+// const bool fooWithHashCodeFieldEqual = fooWithHashCodeField1 == fooWithHashCodeField2;
+// ^
+// pkg/front_end/testcases/general/constants/various.dart:144:12: Context: While analyzing:
+// const bool fooWithHashCodeFieldEqual = fooWithHashCodeField1 == fooWithHashCodeField2;
+// ^
+//
+// pkg/front_end/testcases/general/constants/various.dart:151:26: Error: Constant evaluation error:
// const int circularity1 = circularity2;
// ^
-// pkg/front_end/testcases/general/constants/various.dart:135:26: Context: Constant expression depends on itself.
+// pkg/front_end/testcases/general/constants/various.dart:151:26: Context: Constant expression depends on itself.
// const int circularity1 = circularity2;
// ^
-// pkg/front_end/testcases/general/constants/various.dart:135:11: Context: While analyzing:
+// pkg/front_end/testcases/general/constants/various.dart:151:11: Context: While analyzing:
// const int circularity1 = circularity2;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:148:7: Error: Constant evaluation error:
+// pkg/front_end/testcases/general/constants/various.dart:164:7: Error: Constant evaluation error:
// const ConstClassWithFailingAssertWithEmptyMessage();
// ^
-// pkg/front_end/testcases/general/constants/various.dart:144:64: Context: This assertion failed with message: (empty)
+// pkg/front_end/testcases/general/constants/various.dart:160:64: Context: This assertion failed with message: (empty)
// const ConstClassWithFailingAssertWithEmptyMessage() : assert(false, "");
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:185:7: Error: Constant evaluation error:
+// pkg/front_end/testcases/general/constants/various.dart:201:7: Error: Constant evaluation error:
// const ConstClassWithFinalFields2();
// ^
-// pkg/front_end/testcases/general/constants/various.dart:181:14: Context: The invocation of 'x' is not allowed in a constant expression.
+// pkg/front_end/testcases/general/constants/various.dart:197:14: Context: The invocation of 'x' is not allowed in a constant expression.
// final z2 = x;
// ^
//
-// pkg/front_end/testcases/general/constants/various.dart:203:35: Error: Constant evaluation error:
+// pkg/front_end/testcases/general/constants/various.dart:219:35: Error: Constant evaluation error:
// const bool.fromEnvironment("foo") ? id1 : willBecomeNull;
// ^
-// pkg/front_end/testcases/general/constants/various.dart:203:35: Context: Expected constant 'null' to be of type 'int Function(int)', but was of type 'Null'.
+// pkg/front_end/testcases/general/constants/various.dart:219:35: Context: Expected constant 'null' to be of type 'int Function(int)', but was of type 'Null'.
// const bool.fromEnvironment("foo") ? id1 : willBecomeNull;
// ^
-// pkg/front_end/testcases/general/constants/various.dart:202:25: Context: While analyzing:
+// pkg/front_end/testcases/general/constants/various.dart:218:25: Context: While analyzing:
// const int Function(int) willBecomeNullToo =
// ^
//
@@ -246,6 +257,14 @@
: self::Foo::x = x, self::Foo::y = "hello".{core::String::length}{core::int}, super core::Object::•()
;
}
+class FooWithHashCodeField extends core::Object /*hasConstConstructor*/ {
+ final field core::int x;
+ final field core::int y;
+ final field core::int hashCode;
+ const constructor •(core::int x) → self::FooWithHashCodeField
+ : self::FooWithHashCodeField::x = x, self::FooWithHashCodeField::y = "hello".{core::String::length}{core::int}, self::FooWithHashCodeField::hashCode = x.{core::num::*}(42){(core::num) → core::int}, super core::Object::•()
+ ;
+}
class ExtendsFoo1 extends self::Foo {
synthetic constructor •() → self::ExtendsFoo1
: invalid-initializer
@@ -253,7 +272,7 @@
}
class ExtendsFoo2 extends self::Foo /*hasConstConstructor*/ {
const constructor •() → self::ExtendsFoo2
- : final dynamic #t1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:121:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+ : final dynamic #t1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:131:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
const ExtendsFoo2();
^^^^^^^^^^^"
;
@@ -392,34 +411,39 @@
const y4 = y++;
^";
static field self::AbstractClassWithConstructor abstractClassWithConstructor = invalid-expression "The class 'AbstractClassWithConstructor' is abstract and can't be instantiated.";
-static const field self::ExtendsFoo1 extendsFoo1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:118:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+static const field self::ExtendsFoo1 extendsFoo1 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:128:39: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
Try using a constructor or factory that is 'const'.
const ExtendsFoo1 extendsFoo1 = const ExtendsFoo1();
^^^^^^^^^^^";
-static const field self::ExtendsFoo2 extendsFoo2 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:121:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
+static const field self::ExtendsFoo2 extendsFoo2 = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:131:9: Error: The superclass, 'Foo', has no unnamed constructor that takes no arguments.
const ExtendsFoo2();
^^^^^^^^^^^";
static const field self::Foo foo1 = #C13;
static const field self::Foo foo2 = #C13;
static const field core::bool foosIdentical = #C2;
static const field core::bool foosEqual = #C2;
-static const field core::Symbol barFoo = #C14;
-static const field core::Symbol barFooEqual = #C15;
-static const field core::Symbol tripleShiftSymbol = #C16;
-static const field core::Symbol symbolWithDots = #C17;
+static const field self::FooWithHashCodeField fooWithHashCodeField1 = #C15;
+static const field self::FooWithHashCodeField fooWithHashCodeField2 = #C15;
+static const field core::bool fooWithHashCodeFieldIdentical = #C2;
+static const field core::bool fooWithHashCodeFieldEqual = invalid-expression "Binary operator '==' requires receiver constant 'FooWithHashCodeField {x: 42, y: 5, hashCode: 1764}' of a type with primitive equality or type 'double', but was of type 'FooWithHashCodeField'.
+ - 'FooWithHashCodeField' is from 'pkg/front_end/testcases/general/constants/various.dart'.";
+static const field core::Symbol barFoo = #C16;
+static const field core::Symbol barFooEqual = #C17;
+static const field core::Symbol tripleShiftSymbol = #C18;
+static const field core::Symbol symbolWithDots = #C19;
static const field core::int circularity1 = invalid-expression "Constant expression depends on itself.";
static const field core::int circularity2 = invalid-expression "Constant expression depends on itself.";
static const field core::int circularity3 = invalid-expression "Constant expression depends on itself.";
static const field core::int circularity4 = invalid-expression "Constant expression depends on itself.";
-static const field invalid-type function_const = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:140:24: Error: Not a constant expression.
+static const field invalid-type function_const = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:156:24: Error: Not a constant expression.
const function_const = () {};
^^";
static field () → Null function_var = () → Null {};
static field self::ConstClassWithFailingAssertWithEmptyMessage failedAssertEmptyMessage = invalid-expression "This assertion failed with message: (empty)";
-static const field self::ClassWithTypeArguments<dynamic, dynamic, dynamic> classWithTypeArguments1 = #C18;
-static const field self::ClassWithTypeArguments<dynamic, dynamic, dynamic> classWithTypeArguments2 = #C19;
+static const field self::ClassWithTypeArguments<dynamic, dynamic, dynamic> classWithTypeArguments1 = #C20;
+static const field self::ClassWithTypeArguments<dynamic, dynamic, dynamic> classWithTypeArguments2 = #C21;
static const field core::bool classWithTypeArgumentsIdentical = #C1;
-static field self::ClassWithNonEmptyConstConstructor classWithNonEmptyConstConstructor = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:168:7: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
+static field self::ClassWithNonEmptyConstConstructor classWithNonEmptyConstConstructor = invalid-expression "pkg/front_end/testcases/general/constants/various.dart:184:7: Error: Cannot invoke a non-'const' constructor where a const expression is expected.
Try using a constructor or factory that is 'const'.
const ClassWithNonEmptyConstConstructor();
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^";
@@ -432,16 +456,16 @@
static const field core::bool zeroPointZeroEqualToZero = #C2;
static const field core::bool zeroEqualToZeroPointZero = #C2;
static const field core::bool nanEqual = #C1;
-static const field dynamic willBecomeNull = #C20;
+static const field dynamic willBecomeNull = #C22;
static const field (core::int) → core::int willBecomeNullToo = invalid-expression "Expected constant 'null' to be of type 'int Function(int)', but was of type 'Null'.";
-static const field (core::int) → core::int partialInstantiation = #C22;
+static const field (core::int) → core::int partialInstantiation = #C24;
static const field core::bool yBool = #C2;
static const field core::bool zBool = #C1;
static const field core::Object maybeInt = #C2;
static const field core::bool isItInt = #C1;
static const field core::Object maybeInt2 = #C2;
static const field core::bool isItInt2 = #C1;
-static const field core::int? maybeInt3 = #C20;
+static const field core::int? maybeInt3 = #C22;
static const field core::bool isItInt3 = #C1;
static method id1<T extends core::Object? = dynamic>(self::id1::T% t) → self::id1::T%
return t;
@@ -466,27 +490,31 @@
#C11 = 1
#C12 = 5
#C13 = self::Foo {x:#C6, y:#C12}
- #C14 = #Foo
- #C15 = #Foo=
- #C16 = #>>>
- #C17 = #I.Have.Dots
- #C18 = self::ClassWithTypeArguments<core::int, core::int, core::int> {}
- #C19 = self::ClassWithTypeArguments<dynamic, dynamic, dynamic> {}
- #C20 = null
- #C21 = static-tearoff self::id1
- #C22 = instantiation #C21 <core::int>
+ #C14 = 1764
+ #C15 = self::FooWithHashCodeField {x:#C6, y:#C12, hashCode:#C14}
+ #C16 = #Foo
+ #C17 = #Foo=
+ #C18 = #>>>
+ #C19 = #I.Have.Dots
+ #C20 = self::ClassWithTypeArguments<core::int, core::int, core::int> {}
+ #C21 = self::ClassWithTypeArguments<dynamic, dynamic, dynamic> {}
+ #C22 = null
+ #C23 = static-tearoff self::id1
+ #C24 = instantiation #C23 <core::int>
}
Extra constant evaluation status:
Evaluated: InstanceGet @ org-dartlang-testcase:///various.dart:111:26 -> IntConstant(5)
-Extra constant evaluation: evaluated: 11, effectively constant: 1
+Evaluated: InstanceGet @ org-dartlang-testcase:///various.dart:120:26 -> IntConstant(5)
+Extra constant evaluation: evaluated: 15, effectively constant: 2
Constructor coverage from constants:
org-dartlang-testcase:///various.dart:
-- ExtendsFoo2. (from org-dartlang-testcase:///various.dart:121:9)
+- ExtendsFoo2. (from org-dartlang-testcase:///various.dart:131:9)
- Foo. (from org-dartlang-testcase:///various.dart:109:9)
- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
-- ConstClassWithFailingAssertWithEmptyMessage. (from org-dartlang-testcase:///various.dart:144:9)
-- ClassWithTypeArguments. (from org-dartlang-testcase:///various.dart:151:9)
-- ConstClassWithFinalFields2. (from org-dartlang-testcase:///various.dart:177:9)
+- FooWithHashCodeField. (from org-dartlang-testcase:///various.dart:118:9)
+- ConstClassWithFailingAssertWithEmptyMessage. (from org-dartlang-testcase:///various.dart:160:9)
+- ClassWithTypeArguments. (from org-dartlang-testcase:///various.dart:167:9)
+- ConstClassWithFinalFields2. (from org-dartlang-testcase:///various.dart:193:9)
diff --git a/pkg/front_end/testcases/general/constants/various.dart.textual_outline.expect b/pkg/front_end/testcases/general/constants/various.dart.textual_outline.expect
index 3d4ccd8..8cdaa8a 100644
--- a/pkg/front_end/testcases/general/constants/various.dart.textual_outline.expect
+++ b/pkg/front_end/testcases/general/constants/various.dart.textual_outline.expect
@@ -138,6 +138,13 @@
const Foo(int x) : this.x = x, this.y = "hello".length;
}
+class FooWithHashCodeField {
+ final int x;
+ final int y;
+ final int hashCode;
+ const FooWithHashCodeField(int x) : this.x = x, this.y = "hello".length, this.hashCode = x * 42;
+}
+
class ExtendsFoo1 extends Foo {}
const ExtendsFoo1 extendsFoo1 = const ExtendsFoo1();
@@ -156,6 +163,14 @@
const bool foosEqual = foo1 == foo2;
+const FooWithHashCodeField fooWithHashCodeField1 = const FooWithHashCodeField(42);
+
+const FooWithHashCodeField fooWithHashCodeField2 = const FooWithHashCodeField(42);
+
+const bool fooWithHashCodeFieldIdentical = identical(fooWithHashCodeField1, fooWithHashCodeField2);
+
+const bool fooWithHashCodeFieldEqual = fooWithHashCodeField1 == fooWithHashCodeField2;
+
const Symbol barFoo = const Symbol("Foo");
const Symbol barFooEqual = const Symbol("Foo=");
diff --git a/pkg/front_end/testcases/records/record_named_constant_evaluation.dart b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart
new file mode 100644
index 0000000..385afc5
--- /dev/null
+++ b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart
@@ -0,0 +1,24 @@
+// Copyright (c) 2024, 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.
+
+// Mostly copied from issue54491.dart.
+
+void main() {
+ const Chk((Ex(1), foo: Ex(2)), eq: (1, foo: 2));
+ const Chk((1, foo: 2), eq: (1, foo: 2));
+ const Chk((Ex(1), foo: Ex(2)), eq: (Ex(1), foo: Ex(2)));
+ const Chk((Ex(1), foo: Ex(2)), eq: (1, foo: 2));
+ const Chk(((1 as Ex), foo: (2 as Ex)), eq: (1, foo: 2));
+ const Chk((Ex(1) as int, foo: Ex(2) as int), eq: (1, foo: 2));
+ const Chk((Ex(1), foo: Ex(2)) as (int, {int foo}), eq: (1, foo: 2));
+ const Chk((1, foo: 2) as (Ex, {int foo}), eq: (1, foo: 2));
+ const Chk(Ex((1, foo: 2)), eq: (1, foo: 2));
+ const Chk(Ex((Ex(1), foo: Ex(2))), eq: (1, foo: 2));
+}
+class Chk {
+ const Chk(Object? v, {required Object? eq}) :
+ assert(v == eq, "Not equal ${(v, eq: eq)}");
+}
+
+extension type const Ex(Object? value) {}
diff --git a/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.strong.expect b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.strong.expect
new file mode 100644
index 0000000..1a68754
--- /dev/null
+++ b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.strong.expect
@@ -0,0 +1,42 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Chk extends core::Object /*hasConstConstructor*/ {
+ const constructor •(core::Object? v, {required core::Object? eq}) → self::Chk
+ : assert(v =={core::Object::==}{(core::Object) → core::bool} eq, "Not equal ${(v, {eq: eq})}"), super core::Object::•()
+ ;
+}
+extension type Ex(core::Object? value) {
+ abstract extension-type-member representation-field get value() → core::Object?;
+ constructor • = self::Ex|constructor#;
+ constructor tearoff • = self::Ex|constructor#_#new#tearOff;
+}
+static method main() → void {
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+}
+static extension-type-member method Ex|constructor#(core::Object? value) → self::Ex% /* erasure=core::Object?, declared=! */ {
+ lowered final self::Ex% /* erasure=core::Object?, declared=! */ #this = value;
+ return #this;
+}
+static extension-type-member method Ex|constructor#_#new#tearOff(core::Object? value) → self::Ex% /* erasure=core::Object?, declared=! */
+ return self::Ex|constructor#(value);
+
+constants {
+ #C1 = self::Chk {}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///record_named_constant_evaluation.dart:
+- Chk. (from org-dartlang-testcase:///record_named_constant_evaluation.dart:20:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.strong.modular.expect b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.strong.modular.expect
new file mode 100644
index 0000000..1a68754
--- /dev/null
+++ b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.strong.modular.expect
@@ -0,0 +1,42 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Chk extends core::Object /*hasConstConstructor*/ {
+ const constructor •(core::Object? v, {required core::Object? eq}) → self::Chk
+ : assert(v =={core::Object::==}{(core::Object) → core::bool} eq, "Not equal ${(v, {eq: eq})}"), super core::Object::•()
+ ;
+}
+extension type Ex(core::Object? value) {
+ abstract extension-type-member representation-field get value() → core::Object?;
+ constructor • = self::Ex|constructor#;
+ constructor tearoff • = self::Ex|constructor#_#new#tearOff;
+}
+static method main() → void {
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+}
+static extension-type-member method Ex|constructor#(core::Object? value) → self::Ex% /* erasure=core::Object?, declared=! */ {
+ lowered final self::Ex% /* erasure=core::Object?, declared=! */ #this = value;
+ return #this;
+}
+static extension-type-member method Ex|constructor#_#new#tearOff(core::Object? value) → self::Ex% /* erasure=core::Object?, declared=! */
+ return self::Ex|constructor#(value);
+
+constants {
+ #C1 = self::Chk {}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///record_named_constant_evaluation.dart:
+- Chk. (from org-dartlang-testcase:///record_named_constant_evaluation.dart:20:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.strong.outline.expect b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.strong.outline.expect
new file mode 100644
index 0000000..798d8be
--- /dev/null
+++ b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.strong.outline.expect
@@ -0,0 +1,22 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Chk extends core::Object /*hasConstConstructor*/ {
+ const constructor •(core::Object? v, {required core::Object? eq}) → self::Chk
+ : assert(v =={core::Object::==}{(core::Object) → core::bool} eq, "Not equal ${(v, {eq: eq})}"), super core::Object::•()
+ ;
+}
+extension type Ex(core::Object? value) {
+ abstract extension-type-member representation-field get value() → core::Object?;
+ constructor • = self::Ex|constructor#;
+ constructor tearoff • = self::Ex|constructor#_#new#tearOff;
+}
+static method main() → void
+ ;
+static extension-type-member method Ex|constructor#(core::Object? value) → self::Ex% /* erasure=core::Object?, declared=! */ {
+ lowered final self::Ex% /* erasure=core::Object?, declared=! */ #this = value;
+ return #this;
+}
+static extension-type-member method Ex|constructor#_#new#tearOff(core::Object? value) → self::Ex% /* erasure=core::Object?, declared=! */
+ return self::Ex|constructor#(value);
diff --git a/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.strong.transformed.expect b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.strong.transformed.expect
new file mode 100644
index 0000000..1a68754
--- /dev/null
+++ b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.strong.transformed.expect
@@ -0,0 +1,42 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+class Chk extends core::Object /*hasConstConstructor*/ {
+ const constructor •(core::Object? v, {required core::Object? eq}) → self::Chk
+ : assert(v =={core::Object::==}{(core::Object) → core::bool} eq, "Not equal ${(v, {eq: eq})}"), super core::Object::•()
+ ;
+}
+extension type Ex(core::Object? value) {
+ abstract extension-type-member representation-field get value() → core::Object?;
+ constructor • = self::Ex|constructor#;
+ constructor tearoff • = self::Ex|constructor#_#new#tearOff;
+}
+static method main() → void {
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+ #C1;
+}
+static extension-type-member method Ex|constructor#(core::Object? value) → self::Ex% /* erasure=core::Object?, declared=! */ {
+ lowered final self::Ex% /* erasure=core::Object?, declared=! */ #this = value;
+ return #this;
+}
+static extension-type-member method Ex|constructor#_#new#tearOff(core::Object? value) → self::Ex% /* erasure=core::Object?, declared=! */
+ return self::Ex|constructor#(value);
+
+constants {
+ #C1 = self::Chk {}
+}
+
+
+Constructor coverage from constants:
+org-dartlang-testcase:///record_named_constant_evaluation.dart:
+- Chk. (from org-dartlang-testcase:///record_named_constant_evaluation.dart:20:9)
+- Object. (from org-dartlang-sdk:///sdk/lib/core/object.dart)
diff --git a/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.textual_outline.expect b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.textual_outline.expect
new file mode 100644
index 0000000..3cebb70
--- /dev/null
+++ b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.textual_outline.expect
@@ -0,0 +1,8 @@
+void main() {}
+
+class Chk {
+ const Chk(Object? v, {required Object? eq})
+ : assert(v == eq, "Not equal ${(v, eq: eq)}");
+}
+
+extension type const Ex(Object? value) {}
diff --git a/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.textual_outline_modelled.expect b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.textual_outline_modelled.expect
new file mode 100644
index 0000000..35c1721
--- /dev/null
+++ b/pkg/front_end/testcases/records/record_named_constant_evaluation.dart.textual_outline_modelled.expect
@@ -0,0 +1,8 @@
+class Chk {
+ const Chk(Object? v, {required Object? eq})
+ : assert(v == eq, "Not equal ${(v, eq: eq)}");
+}
+
+extension type const Ex(Object? value) {}
+
+void main() {}
diff --git a/pkg/front_end/tool/coverage_merger.dart b/pkg/front_end/tool/coverage_merger.dart
index ab39df9..e2679c4 100644
--- a/pkg/front_end/tool/coverage_merger.dart
+++ b/pkg/front_end/tool/coverage_merger.dart
@@ -6,7 +6,7 @@
import 'dart:typed_data';
import 'package:_fe_analyzer_shared/src/scanner/characters.dart'
- show $SPACE, $CARET;
+ show $SPACE, $CARET, $LF, $CR;
import 'package:_fe_analyzer_shared/src/scanner/token.dart';
import 'package:front_end/src/util/parser_ast.dart';
import 'package:front_end/src/util/parser_ast_helper.dart';
@@ -16,20 +16,29 @@
import '../test/coverage_helper.dart';
import 'interval_list.dart';
import 'parser_ast_indexer.dart';
+import 'utils.dart';
void main(List<String> arguments) {
Uri? coverageUri;
Uri? packagesUri;
+ bool addCommentsToFiles = false;
+ bool removeCommentsFromFiles = false;
for (String argument in arguments) {
const String coverage = "--coverage=";
const String packages = "--packages=";
+ const String comment = "--comment";
+ const String removeComments = "--remove-comments";
if (argument.startsWith(coverage)) {
coverageUri =
Uri.base.resolveUri(Uri.file(argument.substring(coverage.length)));
} else if (argument.startsWith(packages)) {
packagesUri =
Uri.base.resolveUri(Uri.file(argument.substring(packages.length)));
+ } else if (argument == comment) {
+ addCommentsToFiles = true;
+ } else if (argument == removeComments) {
+ removeCommentsFromFiles = true;
} else {
throw "Unsupported argument: $argument";
}
@@ -42,7 +51,15 @@
}
Stopwatch stopwatch = new Stopwatch()..start();
- mergeFromDirUri(packagesUri, coverageUri, silent: false);
+ mergeFromDirUri(
+ packagesUri,
+ coverageUri,
+ silent: false,
+ extraCoverageIgnores: ["coverage-ignore(suite):"],
+ extraCoverageBlockIgnores: ["coverage-ignore-block(suite):"],
+ addCommentsToFiles: addCommentsToFiles,
+ removeCommentsFromFiles: removeCommentsFromFiles,
+ );
print("Done in ${stopwatch.elapsed}");
}
@@ -50,6 +67,10 @@
Uri packagesUri,
Uri coverageUri, {
required bool silent,
+ required List<String> extraCoverageIgnores,
+ required List<String> extraCoverageBlockIgnores,
+ bool addCommentsToFiles = false,
+ bool removeCommentsFromFiles = false,
}) {
void output(Object? object) {
if (silent) return;
@@ -116,16 +137,34 @@
for (Uri uri in knownUris.toList()
..sort(((a, b) => a.toString().compareTo(b.toString())))) {
// Don't care about coverage for testing stuff.
- if (uri.toString().startsWith("package:front_end/src/testing/")) continue;
+ String uriString = uri.toString();
+ if (uriString.startsWith("package:front_end/src/testing/")) continue;
+ if (uriString == "package:front_end/src/util/parser_ast_helper.dart" ||
+ uriString ==
+ "package:front_end/src/api_prototype/experimental_flags_generated.dart" ||
+ uriString == "package:front_end/src/codes/cfe_codes_generated.dart") {
+ continue;
+ }
Hit? hit = hits[uri];
Set<int>? miss = misses[uri];
List<int> hitsSorted =
hit == null ? const [] : (hit._data.keys.toList()..sort());
- CoverageInfo processInfo =
- process(packageConfig, uri, miss ?? const {}, hitsSorted);
- output(processInfo.visualization);
+ CoverageInfo processInfo = process(
+ packageConfig,
+ uri,
+ miss ?? const {},
+ hitsSorted,
+ extraCoverageIgnores,
+ extraCoverageBlockIgnores,
+ addCommentsToFiles: addCommentsToFiles,
+ removeCommentsFromFiles: removeCommentsFromFiles,
+ );
+ if (processInfo.visualization.trim().isNotEmpty) {
+ output(processInfo.visualization);
+ output("");
+ }
result[uri] = processInfo;
filesCount++;
if (processInfo.error) {
@@ -137,8 +176,6 @@
hitsTotal += processInfo.hitCount;
missesTotal += processInfo.missCount;
}
-
- output("");
}
output("Processed $filesCount files with $errorsCount error(s) and "
@@ -170,8 +207,16 @@
: error = false;
}
-CoverageInfo process(PackageConfig packageConfig, Uri uri,
- Set<int> untrimmedMisses, List<int> hitsSorted) {
+CoverageInfo process(
+ PackageConfig packageConfig,
+ Uri uri,
+ Set<int> untrimmedMisses,
+ List<int> hitsSorted,
+ List<String> extraCoverageIgnores,
+ List<String> extraCoverageBlockIgnores, {
+ bool addCommentsToFiles = false,
+ bool removeCommentsFromFiles = false,
+}) {
Uri? fileUri = packageConfig.resolve(uri);
if (fileUri == null) {
return new CoverageInfo.error("Couldn't find file uri for $uri");
@@ -193,11 +238,200 @@
enableExtensionMethods: true,
enableNonNullable: true,
enableTripleShift: true,
+ allowPatterns: true,
lineStarts: lineStarts,
);
+ Source source = new Source(lineStarts, rawBytes, uri, fileUri);
+
+ if (removeCommentsFromFiles) {
+ CompilationUnitBegin unitBegin =
+ ast.children!.first as CompilationUnitBegin;
+ Token? token = unitBegin.token;
+ List<Token> removeComments = [];
+ while (token != null && !token.isEof) {
+ Token? comment = token.precedingComments;
+ while (comment != null) {
+ String message = comment.lexeme.trim().toLowerCase();
+ while (message.startsWith("//") || message.startsWith("/*")) {
+ message = message.substring(2).trim();
+ }
+ for (String coverageIgnoreString in const [
+ "coverage-ignore(suite): not run.",
+ "coverage-ignore-block(suite): not run.",
+ ]) {
+ if (message.startsWith(coverageIgnoreString)) {
+ removeComments.add(comment);
+ }
+ }
+ comment = comment.next;
+ }
+ token = token.next;
+ }
+ String sourceText = source.text;
+ StringBuffer sb = new StringBuffer();
+ int from = 0;
+ for (Token token in removeComments) {
+ String substring = sourceText.substring(from, token.charOffset);
+ sb.write(substring);
+ from = token.charEnd;
+ // Remove whitespace after too.
+ while (sourceText.length > from &&
+ (sourceText.codeUnitAt(from) == $SPACE ||
+ sourceText.codeUnitAt(from) == $LF ||
+ sourceText.codeUnitAt(from) == $CR)) {
+ from++;
+ }
+ }
+ sb.write(sourceText.substring(from));
+ f.writeAsStringSync(sb.toString());
+ print("Removed ${removeComments.length} in $uri");
+
+ // Return a fake result.
+ return new CoverageInfo(
+ allCovered: true, missCount: -1, hitCount: -1, visualization: "fake 2");
+ }
+
+ List<int> allSorted = [...hitsSorted, ...untrimmedMisses]..sort();
AstIndexerAndIgnoreCollector astIndexer =
- AstIndexerAndIgnoreCollector.collect(ast);
+ AstIndexerAndIgnoreCollector.collect(
+ ast, extraCoverageIgnores, extraCoverageBlockIgnores,
+ hitsSorted: hitsSorted, allSorted: allSorted);
+
+ IntervalList ignoredIntervals =
+ astIndexer.ignoredStartEnd.buildIntervalList();
+
+ if (addCommentsToFiles) {
+ String sourceText = source.text;
+ StringBuffer sb = new StringBuffer();
+ int from = 0;
+ astIndexer.potentiallyAddCommentTokens.sort();
+ List<_CommentOn> processed = [];
+ for (_CommentOn commentOn in astIndexer.potentiallyAddCommentTokens) {
+ bool doAdd = true;
+ if (processed.isNotEmpty) {
+ _CommentOn prevAdded = processed.last;
+
+ if (prevAdded.beginToken.charOffset <=
+ commentOn.beginToken.charOffset &&
+ prevAdded.endToken.charEnd >= commentOn.endToken.charEnd) {
+ // The previous added "block" contain this one.
+ doAdd = false;
+
+ if (commentOn.commentOnToken.lexeme == "." ||
+ commentOn.commentOnToken.lexeme == "?.") {
+ // A comment on the actual call isn't pretty.
+ // Allow the "bigger one".
+ } else if (prevAdded.canBeReplaced) {
+ // Though if there aren't any possible extra coverage in the
+ // previous block compared to this one, we do prefer the smaller
+ // one.
+ int allSortedIndex =
+ binarySearch(allSorted, commentOn.beginToken.charOffset);
+ if (allSortedIndex < allSorted.length &&
+ allSorted[allSortedIndex] < commentOn.beginToken.charOffset) {
+ allSortedIndex++;
+ }
+ if (allSortedIndex > 0 &&
+ allSorted[allSortedIndex - 1] <
+ prevAdded.beginToken.charOffset) {
+ // The block before this can't have any coverage.
+ // Now find the first point outside this range.
+ int i = binarySearch(allSorted, commentOn.endToken.charEnd) + 1;
+ if (i < allSorted.length &&
+ allSorted[i] > prevAdded.endToken.charEnd) {
+ // The previous one doesn't have any possible coverage points
+ // that this one doesn't. We prefer the smaller one and will
+ // therefore replace it.
+ processed.removeLast();
+ doAdd = true;
+ }
+ }
+ }
+ }
+ }
+ if (doAdd) {
+ processed.add(commentOn);
+ }
+ }
+ for (_CommentOn entry in processed) {
+ // If - on a file without ignore comments - an ignore comment is
+ // pushed down (say inside an if instead of outside it), on a subsequent
+ // run, because now that ignore inside the if is already present there's
+ // nothing to push down and the one outside the if will be added.
+ // We don't want that, so verify that a new comment will actually ignore
+ // possible coverage points that wasn't covered/ignored before.
+ int sortedIndex = binarySearch(allSorted, entry.beginToken.charOffset);
+ if (sortedIndex < allSorted.length &&
+ allSorted[sortedIndex] < entry.beginToken.charOffset) {
+ sortedIndex++;
+ }
+ bool doAdd = false;
+ while (sortedIndex < allSorted.length &&
+ allSorted[sortedIndex] <= entry.endToken.charEnd) {
+ if (!ignoredIntervals.contains(allSorted[sortedIndex])) {
+ doAdd = true;
+ break;
+ }
+ sortedIndex++;
+ }
+
+ if (!doAdd) {
+ continue;
+ }
+
+ Token token = entry.commentOnToken;
+ String extra = "";
+ if (token.previous?.lexeme == "&&" ||
+ token.previous?.lexeme == "||" ||
+ token.previous?.lexeme == "(" ||
+ token.previous?.lexeme == ")" ||
+ token.previous?.lexeme == "}" ||
+ token.previous?.lexeme == "?" ||
+ token.previous?.lexeme == ":" ||
+ token.previous?.lexeme == ";" ||
+ token.previous?.lexeme == "=" ||
+ token.lexeme == "?.") {
+ extra = "\n ";
+ // If adding an extra linebreak would introduce an empty line we won't
+ // add it.
+ for (int i = token.charOffset - 1; i >= token.previous!.charEnd; i--) {
+ int codeUnit = sourceText.codeUnitAt(i);
+ if (codeUnit == $SPACE) {
+ // We ignore spaces.
+ } else if (codeUnit == $LF || codeUnit == $CR) {
+ // Found linebreak: Adding a linebreak would add an empty line.
+ extra = "";
+ break;
+ } else {
+ // We found a non-space before a linebreak.
+ // Let's just add the linebreak.
+ break;
+ }
+ }
+ }
+ if (token.precedingComments != null) {
+ token = token.precedingComments!;
+ }
+ String substring = sourceText.substring(from, token.charOffset);
+ sb.write(substring);
+
+ // The extra spaces at the end makes the formatter format better if for
+ // instance there's comments after this.
+ if (entry.isBlock) {
+ sb.write("$extra// Coverage-ignore-block(suite): Not run.\n ");
+ } else {
+ sb.write("$extra// Coverage-ignore(suite): Not run.\n ");
+ }
+ from = token.charOffset;
+ }
+ sb.write(sourceText.substring(from));
+ f.writeAsStringSync(sb.toString());
+
+ // Return a fake result.
+ return new CoverageInfo(
+ allCovered: true, missCount: -1, hitCount: -1, visualization: "fake");
+ }
// TODO(jensj): Extract all comments and use those as well here.
// TODO(jensj): Should some comment throw/report and error if covered?
@@ -205,8 +439,6 @@
StringBuffer visualization = new StringBuffer();
- IntervalList ignoredIntervals =
- astIndexer.ignoredStartEnd.buildIntervalList();
var (:bool allCovered, :Set<int> trimmedMisses) =
_trimIgnoredAndPrintPercentages(
visualization, ignoredIntervals, untrimmedMisses, hitsSorted, uri);
@@ -221,7 +453,6 @@
CompilationUnitBegin unitBegin = ast.children!.first as CompilationUnitBegin;
Token firstToken = unitBegin.token;
- Source source = new Source(lineStarts, rawBytes, uri, fileUri);
List<int> sortedMisses = trimmedMisses.toList()..sort();
@@ -285,8 +516,8 @@
String? name = astIndexer.nameOfEntitySpanning(offset);
if (name != null) {
- visualization.writeln(
- "$uri:${location.line}: No coverage for '$name'.\n$line\n");
+ visualization.writeln("$uri:${location.line}: "
+ "No coverage for '$name' ($offset).\n$line\n");
// TODO(jensj): Squiggly line under the identifier of the entity?
} else {
visualization.writeln(
@@ -371,7 +602,7 @@
"($missCount misses)");
return (allCovered: false, trimmedMisses: trimmedMisses);
} else {
- visualization.writeln("$uri: 100% (OK)");
+ // visualization.writeln("$uri: 100% (OK)");
return (allCovered: true, trimmedMisses: trimmedMisses);
}
}
@@ -423,15 +654,32 @@
"debugName",
"writeNullabilityOn",
};
+ final List<String> _coverageIgnores = [
+ "coverage-ignore:",
+ ];
+ final List<String> _coverageBlockIgnores = [
+ "coverage-ignore-block:",
+ ];
final IntervalListBuilder ignoredStartEnd = new IntervalListBuilder();
+ final List<int> hitsSorted;
+ int hitsSortedIndex = 0;
+ final List<int> allSorted;
+ int allSortedIndex = 0;
+
+ final List<_CommentOn> potentiallyAddCommentTokens = [];
+
late final _AstIndexerAndIgnoreCollectorBody _collectorBody =
new _AstIndexerAndIgnoreCollectorBody(this);
- static AstIndexerAndIgnoreCollector collect(ParserAstNode ast) {
+ static AstIndexerAndIgnoreCollector collect(ParserAstNode ast,
+ List<String> extraCoverageIgnores, List<String> extraCoverageBlockIgnores,
+ {required List<int> hitsSorted, required List<int> allSorted}) {
AstIndexerAndIgnoreCollector collector =
- new AstIndexerAndIgnoreCollector._();
+ new AstIndexerAndIgnoreCollector._(hitsSorted, allSorted);
+ collector._coverageIgnores.addAll(extraCoverageIgnores);
+ collector._coverageBlockIgnores.addAll(extraCoverageBlockIgnores);
ast.accept(collector);
assert(collector.positionNodeIndex.length ==
@@ -442,10 +690,228 @@
return collector;
}
- AstIndexerAndIgnoreCollector._() {}
+ AstIndexerAndIgnoreCollector._(this.hitsSorted, this.allSorted) {}
+
+ bool _hasIgnoreComment(Token tokenWithPossibleComment,
+ {required bool isBlock}) {
+ List<String> coverageIgnores = _coverageIgnores;
+ if (isBlock) {
+ coverageIgnores = _coverageBlockIgnores;
+ }
+ Token? comment = tokenWithPossibleComment.precedingComments;
+ while (comment != null) {
+ String message = comment.lexeme.trim().toLowerCase();
+ while (message.startsWith("//") || message.startsWith("/*")) {
+ message = message.substring(2).trim();
+ }
+ for (String coverageIgnoreString in coverageIgnores) {
+ if (message.startsWith(coverageIgnoreString)) {
+ return true;
+ }
+ }
+ comment = comment.next;
+ }
+ return false;
+ }
+
+ /// Check if there is an ignore comment on [tokenWithPossibleComment] and
+ /// returns true if there is.
+ ///
+ /// If there is not it will add a note to add one if that makes sense (in that
+ /// there is possible coverage but no actual coverage).
+ bool _checkCommentAndIgnoreCoverage(
+ Token tokenWithPossibleComment, BeginAndEndTokenParserAstNode ignoreRange,
+ {required bool allowReplace}) {
+ return _checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ tokenWithPossibleComment, ignoreRange.beginToken, ignoreRange.endToken,
+ allowReplace: allowReplace);
+ }
+
+ /// Check if there is an ignore comment on [tokenWithPossibleComment] and
+ /// returns true if there is.
+ ///
+ /// If there is not it will add a note to add one if that makes sense (in that
+ /// there is possible coverage but no actual coverage).
+ bool _checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ Token tokenWithPossibleComment, Token beginToken, Token endToken,
+ {required bool allowReplace,
+ bool isBlock = false,
+ bool allowOnBraceStart = false}) {
+ if (_hasIgnoreComment(tokenWithPossibleComment, isBlock: isBlock)) {
+ ignoredStartEnd.addIntervalIncludingEnd(
+ beginToken.charOffset, endToken.charEnd);
+ return true;
+ }
+
+ // Should a comment be added here?
+ if (tokenWithPossibleComment.lexeme == "{" && !allowOnBraceStart) {
+ // We don't want to add it "outside" the block, but inside it,
+ // so we just return here.
+ return false;
+ }
+ if (tokenWithPossibleComment.lexeme == "else" &&
+ tokenWithPossibleComment.next!.lexeme == "{") {
+ // An else with a block, prefer it directly inside the block instead.
+ return false;
+ }
+ // Because of (at least) `visitEndingBinaryExpressionHandle` we can get
+ // events out of order. Go back here if needed...
+ if (allSorted.isNotEmpty) {
+ if (allSorted.length >= allSortedIndex) {
+ allSortedIndex = allSorted.length - 1;
+ }
+ while (allSortedIndex > 0 &&
+ allSorted[allSortedIndex] > beginToken.charOffset) {
+ allSortedIndex--;
+ }
+ // ...then go forward if needed (e.g. when it does come in order).
+ while (allSortedIndex < allSorted.length &&
+ allSorted[allSortedIndex] < beginToken.charOffset) {
+ allSortedIndex++;
+ }
+ }
+
+ if (allSortedIndex >= allSorted.length ||
+ allSorted[allSortedIndex] > endToken.charEnd) {
+ // Nothing inside this block can be covered by the VM anyway.
+ return false;
+ }
+
+ // As before: Make work when events arrive out of order.
+ if (hitsSorted.isNotEmpty) {
+ if (hitsSorted.length >= hitsSortedIndex) {
+ hitsSortedIndex = hitsSorted.length - 1;
+ }
+ while (hitsSortedIndex > 0 &&
+ hitsSorted[hitsSortedIndex] > beginToken.charOffset) {
+ hitsSortedIndex--;
+ }
+ while (hitsSortedIndex < hitsSorted.length &&
+ hitsSorted[hitsSortedIndex] < beginToken.charOffset) {
+ hitsSortedIndex++;
+ }
+ }
+
+ if (hitsSortedIndex >= hitsSorted.length ||
+ hitsSorted[hitsSortedIndex] > endToken.charEnd) {
+ // No hits at all or next hit is after this "block".
+ potentiallyAddCommentTokens.add(new _CommentOn(
+ commentOnToken: tokenWithPossibleComment,
+ beginToken: beginToken,
+ endToken: endToken,
+ canBeReplaced: allowReplace,
+ isBlock: isBlock,
+ ));
+ }
+
+ return false;
+ }
+
+ /// Check if there is an ignore comment on [tokenWithPossibleComment] and
+ /// returns true if there is.
+ ///
+ /// If there is not it will add a note to add one if that makes sense (in that
+ /// there is possible coverage but no actual coverage).
+ ///
+ /// This method in particular will try to ignore from
+ /// [tokenWithPossibleComment] until the end of the block that it's inside,
+ /// but fall back to the original range if that's not possible.
+ /// Two different comments are used to distinguish these cases.
+ bool _checkCommentAndIgnoreCoverageUntilEndOfBlockOrEnd(
+ Token tokenWithPossibleComment,
+ Token beginToken,
+ ParserAstNode node,
+ Token endToken,
+ {required bool allowReplace}) {
+ ParserAstNode? parent = node.parent;
+ if ((parent is BlockFunctionBodyEnd || parent is BlockEnd)) {
+ if (_checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ tokenWithPossibleComment,
+ beginToken,
+ (parent as BeginAndEndTokenParserAstNode).endToken,
+ allowReplace: allowReplace,
+ isBlock: true)) {
+ return true;
+ }
+ }
+ return _checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ tokenWithPossibleComment, beginToken, endToken,
+ allowReplace: allowReplace);
+ }
+
+ bool _ignoreIfChildrenIsThrow(BeginAndEndTokenParserAstNode node) {
+ List<ParserAstNode>? children = node.children;
+ if (children == null) return false;
+ if (children.length >= 4 &&
+ children[1] is NewExpressionEnd &&
+ children[2] is ThrowExpressionHandle &&
+ children[3] is ExpressionStatementHandle) {
+ ignoredStartEnd.addIntervalIncludingEnd(
+ node.beginToken.charOffset, node.endToken.charEnd);
+ return true;
+ }
+ return false;
+ }
+
+ @override
+ void visitClassDeclarationEnd(ClassDeclarationEnd node) {
+ // Note that this stops recursing meaning there'll be stuff we can't look
+ // up. If that turns out to be a problem we can likely just not return,
+ // possible "double-ignored" coverages should still work fine because of the
+ // interval list.
+ if (_checkCommentAndIgnoreCoverage(node.beginToken, node,
+ allowReplace: false)) return;
+ super.visitClassDeclarationEnd(node);
+ }
+
+ @override
+ void visitExtensionDeclarationEnd(ExtensionDeclarationEnd node) {
+ // Note that this stops recursing meaning there'll be stuff we can't look
+ // up. If that turns out to be a problem we can likely just not return,
+ // possible "double-ignored" coverages should still work fine because of the
+ // interval list.
+ if (_checkCommentAndIgnoreCoverage(node.beginToken, node,
+ allowReplace: false)) return;
+ super.visitExtensionDeclarationEnd(node);
+ }
+
+ @override
+ void visitExtensionTypeDeclarationEnd(ExtensionTypeDeclarationEnd node) {
+ // Note that this stops recursing meaning there'll be stuff we can't look
+ // up. If that turns out to be a problem we can likely just not return,
+ // possible "double-ignored" coverages should still work fine because of the
+ // interval list.
+ if (_checkCommentAndIgnoreCoverage(node.beginToken, node,
+ allowReplace: false)) return;
+ super.visitExtensionTypeDeclarationEnd(node);
+ }
+
+ @override
+ void visitTopLevelFieldsEnd(TopLevelFieldsEnd node) {
+ super.visitTopLevelFieldsEnd(node);
+ assert(positionNodeIndex.last == node);
+ assert(positionStartEndIndex.last == node.endToken.charEnd);
+ int index = positionNodeIndex.length - 1;
+ int firstIndex = moveNodeIndexToFirstMetadataIfAny(index)!;
+ Token beginToken = node.beginToken;
+ if (firstIndex < index) {
+ MetadataEnd metadata = positionNodeIndex[firstIndex] as MetadataEnd;
+ beginToken = metadata.beginToken;
+ }
+
+ if (_checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.beginToken, beginToken, node.endToken,
+ allowReplace: false)) {
+ // Ignore these class fields including metadata.
+ ignoredStartEnd.addIntervalIncludingEnd(
+ positionStartEndIndex[firstIndex * 2 + 0], node.endToken.charEnd);
+ }
+ }
@override
void visitTopLevelMethodEnd(TopLevelMethodEnd node) {
+ if (_checkCommentAndIgnoreCoverage(node.beginToken, node,
+ allowReplace: false)) return;
super.visitTopLevelMethodEnd(node);
String name = node.getNameIdentifier().token.lexeme;
if (topLevelMethodNamesToIgnore.contains(name)) {
@@ -461,15 +927,63 @@
}
}
+ /// This method will try to recognize entities (think methods) that just
+ /// throws. If it finds [node] to be this, it will add it to the ignore list
+ /// and return true.
+ bool _ignoreIfEntityWithThrowBody(BeginAndEndTokenParserAstNode node) {
+ List<ParserAstNode>? children = node.children;
+ if (children == null) return false;
+ for (ParserAstNode child in children) {
+ if (child is BlockFunctionBodyEnd && _ignoreIfChildrenIsThrow(child)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @override
+ void containerFields(
+ BeginAndEndTokenParserAstNode node, List<IdentifierHandle> names) {
+ super.containerFields(node, names);
+ assert(positionNodeIndex.last == node);
+ assert(positionStartEndIndex.last == node.endToken.charEnd);
+ int index = positionNodeIndex.length - 1;
+ int firstIndex = moveNodeIndexToFirstMetadataIfAny(index)!;
+ Token beginToken = node.beginToken;
+ if (firstIndex < index) {
+ MetadataEnd metadata = positionNodeIndex[firstIndex] as MetadataEnd;
+ beginToken = metadata.beginToken;
+ }
+
+ if (_checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.beginToken, beginToken, node.endToken,
+ allowReplace: false)) {
+ // Ignore these class fields including metadata.
+ ignoredStartEnd.addIntervalIncludingEnd(
+ positionStartEndIndex[firstIndex * 2 + 0], node.endToken.charEnd);
+ }
+ }
+
@override
void containerMethod(BeginAndEndTokenParserAstNode node, String name) {
super.containerMethod(node, name);
- if (classMethodNamesToIgnore.contains(name)) {
+ assert(positionNodeIndex.last == node);
+ assert(positionStartEndIndex.last == node.endToken.charEnd);
+ int index = positionNodeIndex.length - 1;
+ int firstIndex = moveNodeIndexToFirstMetadataIfAny(index)!;
+ Token beginToken = node.beginToken;
+ if (firstIndex < index) {
+ MetadataEnd metadata = positionNodeIndex[firstIndex] as MetadataEnd;
+ beginToken = metadata.beginToken;
+ }
+
+ if (_ignoreIfEntityWithThrowBody(node) ||
+ classMethodNamesToIgnore.contains(name) ||
+ _checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.beginToken, beginToken, node.endToken,
+ allowReplace: false)) {
// Ignore this class method including metadata.
- assert(positionNodeIndex.last == node);
- assert(positionStartEndIndex.last == node.endToken.charEnd);
- int index = positionNodeIndex.length - 1;
- int firstIndex = moveNodeIndexToFirstMetadataIfAny(index)!;
+
ignoredStartEnd.addIntervalIncludingEnd(
positionStartEndIndex[firstIndex * 2 + 0], node.endToken.charEnd);
} else {
@@ -506,18 +1020,340 @@
return true;
}
}
+ if (_collector._ignoreIfChildrenIsThrow(node)) return true;
return false;
}
@override
void visitReturnStatementEnd(ReturnStatementEnd node) {
if (_recordIfIsCallToNotExpectedCoverage(node)) return;
+ if (_collector._checkCommentAndIgnoreCoverage(node.beginToken, node,
+ allowReplace: false)) {
+ return;
+ }
super.visitReturnStatementEnd(node);
}
@override
void visitBlockEnd(BlockEnd node) {
if (_recordIfIsCallToNotExpectedCoverage(node)) return;
+ if (_collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.beginToken.next!, node.beginToken, node.endToken,
+ allowReplace: false, isBlock: true)) {
+ return;
+ }
super.visitBlockEnd(node);
}
+
+ @override
+ void visitBlockFunctionBodyEnd(BlockFunctionBodyEnd node) {
+ if (_recordIfIsCallToNotExpectedCoverage(node)) return;
+ if (_collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.beginToken.next!, node.beginToken, node.endToken,
+ allowReplace: false, isBlock: true)) {
+ return;
+ }
+ super.visitBlockFunctionBodyEnd(node);
+ }
+
+ @override
+ void visitFunctionExpressionEnd(FunctionExpressionEnd node) {
+ if (_collector._checkCommentAndIgnoreCoverage(node.beginToken, node,
+ allowReplace: true)) {
+ return;
+ }
+ super.visitFunctionExpressionEnd(node);
+ }
+
+ @override
+ void visitLocalFunctionDeclarationEnd(LocalFunctionDeclarationEnd node) {
+ ParserAstNode? beginNode = node.children?.firstOrNull;
+ if (beginNode is LocalFunctionDeclarationBegin) {
+ if (_collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ beginNode.token, beginNode.token, node.endToken,
+ allowReplace: true)) {
+ return;
+ }
+ }
+ super.visitLocalFunctionDeclarationEnd(node);
+ }
+
+ @override
+ void visitSwitchCaseEnd(SwitchCaseEnd node) {
+ if (_collector._checkCommentAndIgnoreCoverage(node.beginToken, node,
+ allowReplace: false)) {
+ return;
+ }
+ super.visitSwitchCaseEnd(node);
+ }
+
+ @override
+ void visitCaseExpressionEnd(CaseExpressionEnd node) {
+ if (_collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.caseKeyword, node.caseKeyword, node.colon,
+ allowReplace: false)) {
+ return;
+ }
+ super.visitCaseExpressionEnd(node);
+ }
+
+ @override
+ void visitThrowExpressionHandle(ThrowExpressionHandle node) {
+ if (_collector._checkCommentAndIgnoreCoverageUntilEndOfBlockOrEnd(
+ node.throwToken, node.throwToken, node, node.endToken,
+ allowReplace: true)) {
+ return;
+ }
+ super.visitThrowExpressionHandle(node);
+ }
+
+ @override
+ void visitElseStatementEnd(ElseStatementEnd node) {
+ if (_collector._checkCommentAndIgnoreCoverage(node.beginToken, node,
+ allowReplace: false)) {
+ return;
+ }
+ super.visitElseStatementEnd(node);
+ }
+
+ @override
+ void visitThenStatementEnd(ThenStatementEnd node) {
+ if (_collector._checkCommentAndIgnoreCoverage(node.beginToken, node,
+ allowReplace: true)) {
+ return;
+ }
+ super.visitThenStatementEnd(node);
+ }
+
+ @override
+ void visitIfStatementEnd(IfStatementEnd node) {
+ if (_collector._checkCommentAndIgnoreCoverageUntilEndOfBlockOrEnd(
+ node.ifToken, node.ifToken, node, node.endToken,
+ allowReplace: true)) {
+ return;
+ }
+ super.visitIfStatementEnd(node);
+ }
+
+ @override
+ void visitTryStatementEnd(TryStatementEnd node) {
+ if (_collector._checkCommentAndIgnoreCoverageUntilEndOfBlockOrEnd(
+ node.tryKeyword, node.tryKeyword, node, node.endToken,
+ allowReplace: true)) {
+ return;
+ }
+ super.visitTryStatementEnd(node);
+ }
+
+ @override
+ void visitBinaryExpressionEnd(BinaryExpressionEnd node) {
+ if (_collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.token.next!, node.token, node.endToken,
+ allowReplace: false)) {
+ return;
+ }
+ super.visitBinaryExpressionEnd(node);
+ }
+
+ @override
+ void visitEndingBinaryExpressionHandle(EndingBinaryExpressionHandle node) {
+ // Given `a?.b` if `a` is null `b` won't execute.
+ // Having the comment before the `?.` formats prettier.
+ if (_collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.token, node.token, node.endToken,
+ allowReplace: true)) {
+ return;
+ }
+ super.visitEndingBinaryExpressionHandle(node);
+ }
+
+ @override
+ void visitThenControlFlowHandle(ThenControlFlowHandle node) {
+ ParserAstNode? parent = node.parent;
+ if (parent is IfControlFlowEnd) {
+ if (_collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.token.next!, node.token.next!, parent.token,
+ allowReplace: false)) {
+ return;
+ }
+ }
+ super.visitThenControlFlowHandle(node);
+ }
+
+ @override
+ void visitConditionalExpressionEnd(ConditionalExpressionEnd node) {
+ // Visiting `foo ? bar : baz`:
+
+ // Check the comment on the `bar` part (i.e. between ? and :).
+ _collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.question.next!, node.question.next!, node.colon,
+ allowReplace: false);
+
+ // Check the comment on the `baz` part (i.e. between : and end).
+ _collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.colon.next!, node.colon.next!, node.endToken,
+ allowReplace: false);
+
+ super.visitConditionalExpressionEnd(node);
+ }
+
+ @override
+ void visitForLoopPartsHandle(ForLoopPartsHandle node) {
+ // Given `for(a; b; c)` --- the `c` part could be uncovered.
+ _collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.rightSeparator.next!,
+ node.rightSeparator.next!,
+ node.leftParen.endGroup!,
+ allowReplace: false);
+ super.visitForLoopPartsHandle(node);
+ }
+
+ @override
+ void visitForInBodyEnd(ForInBodyEnd node) {
+ ParserAstNode? beginNode = node.children?.firstOrNull;
+ if (beginNode is ForInBodyBegin) {
+ if (_collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ beginNode.token, beginNode.token, node.endToken,
+ allowReplace: true, allowOnBraceStart: true)) {
+ return;
+ }
+ }
+ super.visitForInBodyEnd(node);
+ }
+
+ @override
+ void visitExpressionStatementHandle(ExpressionStatementHandle node) {
+ // TODO(jensj): allowReplace should depend upon if there's anything
+ // coverable in this statement. If there isn't it should certainly be
+ // replaceable.
+ if (_collector._checkCommentAndIgnoreCoverageUntilEndOfBlockOrEnd(
+ node.beginToken, node.beginToken, node, node.endToken,
+ allowReplace: false)) {
+ return;
+ }
+ super.visitExpressionStatementHandle(node);
+ }
+
+ @override
+ void visitVariablesDeclarationEnd(VariablesDeclarationEnd node) {
+ // TODO(jensj): allowReplace should depend upon if there's anything
+ // coverable in this statement. If there isn't it should certainly be
+ // replaceable.
+ if (node.endToken != null) {
+ List<ParserAstNode> parentChildren = node.parent!.children!;
+ int thisIndex = parentChildren.indexOf(node);
+ if (thisIndex - 1 >= 0 && parentChildren[thisIndex - 1] is TypeHandle) {
+ TypeHandle type = parentChildren[thisIndex - 1] as TypeHandle;
+ if (_collector._checkCommentAndIgnoreCoverageUntilEndOfBlockOrEnd(
+ type.beginToken, type.beginToken, node, node.endToken!,
+ allowReplace: false)) {
+ return;
+ }
+ }
+ }
+ super.visitVariablesDeclarationEnd(node);
+ }
+
+ @override
+ void visitAssertEnd(AssertEnd node) {
+ if (_collector._checkCommentAndIgnoreCoverageUntilEndOfBlockOrEnd(
+ node.assertKeyword, node.assertKeyword, node, node.endToken,
+ allowReplace: true)) {
+ return;
+ }
+
+ if (node.commaToken != null) {
+ _collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.commaToken!.next!, node.commaToken!, node.endToken,
+ allowReplace: false);
+ }
+ super.visitAssertEnd(node);
+ }
+
+ @override
+ void visitCatchBlockHandle(CatchBlockHandle node) {
+ // TODO(jensj): allowReplace should depend upon if there's anything
+ // coverable in this statement. If there isn't it should certainly be
+ // replaceable.
+ if (node.onKeyword != null) {
+ List<ParserAstNode> parentChildren = node.parent!.children!;
+ int thisIndex = parentChildren.indexOf(node);
+ if (thisIndex - 1 >= 0 && parentChildren[thisIndex - 1] is BlockEnd) {
+ BlockEnd block = parentChildren[thisIndex - 1] as BlockEnd;
+ if (_collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.onKeyword!, node.onKeyword!, block.endToken,
+ allowReplace: false)) {
+ return;
+ }
+ }
+ }
+ super.visitCatchBlockHandle(node);
+ }
+
+ @override
+ void visitPatternEnd(PatternEnd node) {
+ ParserAstNode? beginNode = node.children?.firstOrNull;
+ if (beginNode is PatternBegin) {
+ Token begin = beginNode.token;
+ if (begin.lexeme != ":") {
+ begin = begin.next!;
+ }
+ if (_collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ begin, begin, node.token,
+ allowReplace: true)) {
+ return;
+ }
+ }
+ super.visitPatternEnd(node);
+ }
+
+ @override
+ void visitSwitchExpressionCaseEnd(SwitchExpressionCaseEnd node) {
+ // The entire thing?
+ if (_collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.beginToken, node.beginToken, node.endToken,
+ allowReplace: true)) {
+ return;
+ }
+
+ // The if-matched part?
+ _collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.arrow.next!, node.arrow.next!, node.endToken,
+ allowReplace: true);
+
+ super.visitSwitchExpressionCaseEnd(node);
+ }
+
+ @override
+ void visitAssignmentExpressionHandle(AssignmentExpressionHandle node) {
+ _collector._checkCommentAndIgnoreCoverageWithBeginAndEnd(
+ node.token.next!, node.token.next!, node.endToken,
+ allowReplace: true, allowOnBraceStart: true);
+ super.visitAssignmentExpressionHandle(node);
+ }
+}
+
+class _CommentOn implements Comparable<_CommentOn> {
+ final Token commentOnToken;
+ final Token beginToken;
+ final Token endToken;
+ final bool canBeReplaced;
+ final bool isBlock;
+
+ _CommentOn({
+ required this.commentOnToken,
+ required this.beginToken,
+ required this.endToken,
+ required this.canBeReplaced,
+ required this.isBlock,
+ });
+
+ @override
+ int compareTo(_CommentOn other) {
+ // Small to big.
+ int result = beginToken.charOffset.compareTo(other.beginToken.charOffset);
+ if (result != 0) return result;
+ // Big to small.
+ return other.endToken.charOffset.compareTo(endToken.charOffset);
+ }
}
diff --git a/pkg/front_end/tool/utils.dart b/pkg/front_end/tool/utils.dart
new file mode 100644
index 0000000..8539667
--- /dev/null
+++ b/pkg/front_end/tool/utils.dart
@@ -0,0 +1,25 @@
+// Copyright (c) 2024, 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.
+
+/// Returns the index in the [list] at which [find] is or should have been.
+///
+/// [list] has to be sorted.
+/// If there are several elements matching what we're looking for it can return
+/// the index to of an arbitrary one of them.
+/// If there is no match the element at the index will be smaller than the data
+/// searched for.
+/// If the input list is empty it will return 0 which is not a valid entry.
+int binarySearch(List<int> list, int find) {
+ int low = 0, high = list.length - 1;
+ while (low < high) {
+ int mid = high - ((high - low) >> 1); // Get middle, rounding up.
+ int pivot = list[mid];
+ if (pivot <= find) {
+ low = mid;
+ } else {
+ high = mid - 1;
+ }
+ }
+ return low;
+}