f9f005cdb9
Change-Id: Ie1faacd66448efe209b35dfd66fded622e59812a Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/110766 Auto-Submit: Bob Nystrom <rnystrom@google.com> Commit-Queue: Bob Nystrom <rnystrom@google.com> Reviewed-by: Nicholas Shahan <nshahan@google.com>
138 lines
4.7 KiB
Dart
138 lines
4.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.
|
|
import 'test_file.dart';
|
|
|
|
/// Matches leading indentation in a string.
|
|
final _indentationRegExp = RegExp(r"^(\s*)");
|
|
|
|
/// Matches a line that contains only a line comment.
|
|
final _lineCommentRegExp = RegExp(r"^\s*//");
|
|
|
|
/// Removes existing static error marker comments in [source] and adds markers
|
|
/// for the given [errors].
|
|
///
|
|
/// If [removeAnalyzer] is `false`, then existing analyzer errors in [source]
|
|
/// are preserved. Likewise for [removeCfe] and CFE errors.
|
|
String updateErrorExpectations(String source, List<StaticError> errors,
|
|
{bool removeAnalyzer, bool removeCfe}) {
|
|
removeAnalyzer ??= true;
|
|
removeCfe ??= true;
|
|
|
|
var existingErrors = ErrorExpectationParser.parse(source);
|
|
var lines = source.split("\n");
|
|
|
|
// Keep track of the indentation on any existing expectation markers. If
|
|
// found, it will try to preserve that indentation.
|
|
var indentation = <int, int>{};
|
|
|
|
// Remove existing markers that should be removed.
|
|
var preservedErrors = <StaticError>[];
|
|
for (var error in existingErrors) {
|
|
for (var i = error.markerStartLine; i <= error.markerEndLine; i++) {
|
|
indentation[i] = _countIndentation(lines[i]);
|
|
|
|
// Null the line instead of removing it so that line numbers in the
|
|
// reported errors are still correct.
|
|
lines[i] = null;
|
|
}
|
|
|
|
// Re-add errors for the portions we intend to preserve.
|
|
var keepCode = !removeAnalyzer && error.code != null;
|
|
var keepMessage = !removeCfe && error.message != null;
|
|
|
|
if (keepCode || keepMessage) {
|
|
preservedErrors.add(StaticError(
|
|
line: error.line,
|
|
column: error.column,
|
|
length: error.length,
|
|
code: keepCode ? error.code : null,
|
|
message: keepMessage ? error.message : null));
|
|
}
|
|
}
|
|
|
|
// Merge the new errors with the preserved ones.
|
|
errors = StaticError.simplify([...errors, ...preservedErrors]);
|
|
|
|
var errorMap = <int, List<StaticError>>{};
|
|
for (var error in errors) {
|
|
// -1 to translate from one-based to zero-based index.
|
|
errorMap.putIfAbsent(error.line - 1, () => []).add(error);
|
|
}
|
|
|
|
// If there are multiple errors on the same line, order them
|
|
// deterministically.
|
|
for (var errorList in errorMap.values) {
|
|
errorList.sort();
|
|
}
|
|
|
|
var previousIndent = 0;
|
|
var result = <String>[];
|
|
for (var i = 0; i < lines.length; i++) {
|
|
// Keep the code.
|
|
if (lines[i] != null) {
|
|
result.add(lines[i]);
|
|
previousIndent = _countIndentation(lines[i]);
|
|
}
|
|
|
|
// Add expectations for any errors reported on this line.
|
|
var errorsHere = errorMap[i];
|
|
if (errorsHere == null) continue;
|
|
for (var error in errorsHere) {
|
|
// Try to indent the line nicely to match either the existing expectation
|
|
// that is being regenerated, or, barring that, the previous line of code.
|
|
var indent = indentation[i + 1] ?? previousIndent;
|
|
|
|
// If the error is to the left of the indent and the "//", sacrifice the
|
|
// indentation.
|
|
if (error.column - 1 < indent + 2) indent = 0;
|
|
|
|
var comment = (" " * indent) + "//";
|
|
|
|
// If the error can't fit in a line comment or doesn't have a length, use
|
|
// an explicit location.
|
|
if (error.length == null) {
|
|
result.add("$comment [error line ${error.line}, column "
|
|
"${error.column}]");
|
|
} else if (error.column <= 2) {
|
|
result.add("$comment [error line ${error.line}, column "
|
|
"${error.column}, length ${error.length}]");
|
|
} else {
|
|
var spacing = " " * (error.column - 1 - 2 - indent);
|
|
// A CFE-only error may not have a length, so treat it as length 1.
|
|
var carets = "^" * (error.length ?? 1);
|
|
result.add("$comment$spacing$carets");
|
|
}
|
|
|
|
if (error.code != null) {
|
|
result.add("$comment [analyzer] ${error.code}");
|
|
}
|
|
|
|
if (error.message != null) {
|
|
var errorLines = error.message.split("\n");
|
|
result.add("$comment [cfe] ${errorLines[0]}");
|
|
for (var errorLine in errorLines.skip(1)) {
|
|
result.add("$comment $errorLine");
|
|
}
|
|
|
|
// If the very next line in the source is a line comment, it would
|
|
// become part of the inserted message. To prevent that, insert a blank
|
|
// line.
|
|
if (i < lines.length - 1 &&
|
|
lines[i + 1] != null &&
|
|
_lineCommentRegExp.hasMatch(lines[i + 1])) {
|
|
result.add("");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return result.join("\n");
|
|
}
|
|
|
|
/// Returns the number of characters of leading spaces in [line].
|
|
int _countIndentation(String line) {
|
|
var match = _indentationRegExp.firstMatch(line);
|
|
return match.group(1).length;
|
|
}
|