157336f7d6
Change-Id: I420145268a8b3451e8bb754d83faf9b0bc42549c Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/112491 Reviewed-by: Bob Nystrom <rnystrom@google.com>
210 lines
6.7 KiB
Dart
210 lines
6.7 KiB
Dart
// Copyright (c) 2019, 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.
|
|
|
|
/// Regenerates the static error test markers inside static error tests based
|
|
/// on the actual errors reported by analyzer and CFE.
|
|
import 'dart:io';
|
|
|
|
import 'package:args/args.dart';
|
|
import 'package:glob/glob.dart';
|
|
|
|
import 'package:test_runner/src/command_output.dart';
|
|
import 'package:test_runner/src/path.dart';
|
|
import 'package:test_runner/src/test_file.dart';
|
|
import 'package:test_runner/src/update_errors.dart';
|
|
import 'package:test_runner/src/utils.dart';
|
|
|
|
const _usage =
|
|
"Usage: dart update_static_error_tests.dart [flags...] <path glob>";
|
|
|
|
Future<void> main(List<String> args) async {
|
|
var parser = ArgParser();
|
|
|
|
parser.addFlag("help", abbr: "h");
|
|
|
|
parser.addFlag("dry-run",
|
|
abbr: "n",
|
|
help: "Print result but do not overwrite any files.",
|
|
negatable: false);
|
|
|
|
parser.addSeparator("Strip expectations out of the tests:");
|
|
parser.addFlag("remove",
|
|
abbr: "r",
|
|
help: "Remove all existing error expectations.",
|
|
negatable: false);
|
|
parser.addFlag("remove-analyzer",
|
|
help: "Remove existing analyzer error expectations.", negatable: false);
|
|
parser.addFlag("remove-cfe",
|
|
help: "Remove existing CFE error expectations.", negatable: false);
|
|
|
|
parser.addSeparator(
|
|
"Insert expectations in the tests based on current front end output:");
|
|
parser.addFlag("insert",
|
|
abbr: "i",
|
|
help: "Insert analyzer and CFE error expectations.",
|
|
negatable: false);
|
|
parser.addFlag("insert-analyzer",
|
|
help: "Insert analyzer error expectations.", negatable: false);
|
|
parser.addFlag("insert-cfe",
|
|
help: "Insert CFE error expectations.", negatable: false);
|
|
|
|
parser.addSeparator("Update combines remove and insert:");
|
|
parser.addFlag("update",
|
|
abbr: "u",
|
|
help: "Replace analyzer and CFE error expectations.",
|
|
negatable: false);
|
|
parser.addFlag("update-analyzer",
|
|
help: "Replace analyzer error expectations.", negatable: false);
|
|
parser.addFlag("update-cfe",
|
|
help: "Replace CFE error expectations.", negatable: false);
|
|
|
|
var results = parser.parse(args);
|
|
|
|
if (results["help"] as bool) {
|
|
print("Regenerates the test markers inside static error tests.");
|
|
print("");
|
|
print(_usage);
|
|
print("");
|
|
print(parser.usage);
|
|
exit(0);
|
|
}
|
|
|
|
var dryRun = results["dry-run"] as bool;
|
|
var removeAnalyzer = results["remove-analyzer"] as bool ||
|
|
results["remove"] as bool ||
|
|
results["update-analyzer"] as bool ||
|
|
results["update"] as bool;
|
|
|
|
var removeCfe = results["remove-cfe"] as bool ||
|
|
results["remove"] as bool ||
|
|
results["update-cfe"] as bool ||
|
|
results["update"] as bool;
|
|
|
|
var insertAnalyzer = results["insert-analyzer"] as bool ||
|
|
results["insert"] as bool ||
|
|
results["update-analyzer"] as bool ||
|
|
results["update"] as bool;
|
|
|
|
var insertCfe = results["insert-cfe"] as bool ||
|
|
results["insert"] as bool ||
|
|
results["update-cfe"] as bool ||
|
|
results["update"] as bool;
|
|
|
|
if (!removeAnalyzer && !removeCfe && !insertAnalyzer && !insertCfe) {
|
|
_usageError(
|
|
parser, "Must provide at least one flag for an operation to perform.");
|
|
}
|
|
|
|
if (results.rest.length != 1) {
|
|
_usageError(
|
|
parser, "Must provide a file path or glob for which tests to update.");
|
|
}
|
|
|
|
var result = results.rest.single;
|
|
// Allow tests to be specified without the extension for compatibility with
|
|
// the regular test runner syntax.
|
|
if (!result.endsWith(".dart")) {
|
|
result += ".dart";
|
|
}
|
|
// Allow tests to be specified either relative to the "tests" directory
|
|
// or relative to the current directory.
|
|
var root = result.startsWith("tests") ? "." : "tests";
|
|
var glob = Glob(result, recursive: true);
|
|
for (var entry in glob.listSync(root: root)) {
|
|
if (!entry.path.endsWith(".dart")) continue;
|
|
|
|
if (entry is File) {
|
|
await _processFile(entry,
|
|
dryRun: dryRun,
|
|
removeAnalyzer: removeAnalyzer,
|
|
removeCfe: removeCfe,
|
|
insertAnalyzer: insertAnalyzer,
|
|
insertCfe: insertCfe);
|
|
}
|
|
}
|
|
}
|
|
|
|
void _usageError(ArgParser parser, String message) {
|
|
stderr.writeln("Usage error: $message");
|
|
stderr.writeln();
|
|
stderr.writeln(_usage);
|
|
stderr.writeln(parser.usage);
|
|
exit(64);
|
|
}
|
|
|
|
Future<void> _processFile(File file,
|
|
{bool dryRun,
|
|
bool removeAnalyzer,
|
|
bool removeCfe,
|
|
bool insertAnalyzer,
|
|
bool insertCfe}) async {
|
|
stdout.write("${file.path}...");
|
|
var source = file.readAsStringSync();
|
|
var testFile = TestFile.parse(Path("."), file.path, source);
|
|
|
|
var errors = <StaticError>[];
|
|
if (insertAnalyzer) {
|
|
stdout.write("\r${file.path} (Running analyzer...)");
|
|
errors.addAll(await _runAnalyzer(file.path, testFile.sharedOptions));
|
|
}
|
|
|
|
if (insertCfe) {
|
|
// Clear the previous line.
|
|
stdout.write("\r${file.path} ");
|
|
stdout.write("\r${file.path} (Running CFE...)");
|
|
errors.addAll(await _runCfe(file.path, testFile.sharedOptions));
|
|
}
|
|
|
|
errors = StaticError.simplify(errors);
|
|
|
|
var result = updateErrorExpectations(source, errors,
|
|
removeAnalyzer: removeAnalyzer, removeCfe: removeCfe);
|
|
|
|
stdout.writeln("\r${file.path} (Updated with ${errors.length} errors)");
|
|
|
|
if (dryRun) {
|
|
print(result);
|
|
} else {
|
|
await file.writeAsString(result);
|
|
}
|
|
}
|
|
|
|
/// Invoke analyzer on [path] and gather all static errors it reports.
|
|
Future<List<StaticError>> _runAnalyzer(
|
|
String path, List<String> options) async {
|
|
// TODO(rnystrom): Running the analyzer command line each time is very slow.
|
|
// Either import the analyzer as a library, or at least invoke it in a batch
|
|
// mode.
|
|
var result = await Process.run("sdk/bin/dartanalyzer$shellScriptExtension", [
|
|
...options,
|
|
"--format=machine",
|
|
path,
|
|
]);
|
|
var errors = <StaticError>[];
|
|
AnalysisCommandOutput.parseErrors(result.stderr as String, errors);
|
|
return errors;
|
|
}
|
|
|
|
/// Invoke CFE on [path] and gather all static errors it reports.
|
|
Future<List<StaticError>> _runCfe(String path, List<String> options) async {
|
|
// TODO(rnystrom): Running the CFE command line each time is slow and wastes
|
|
// time generating code, which we don't care about. Import it as a library or
|
|
// at least run it in batch mode.
|
|
var result = await Process.run("sdk/bin/dart", [
|
|
"pkg/front_end/tool/_fasta/compile.dart",
|
|
...options,
|
|
"--verify",
|
|
path,
|
|
]);
|
|
|
|
var errors = <StaticError>[];
|
|
FastaCommandOutput.parseErrors(result.stdout as String, errors);
|
|
|
|
// Running the above command generates a dill file next to the test, which we
|
|
// don't want, so delete it.
|
|
await File("$path.dill").delete();
|
|
|
|
return errors;
|
|
}
|