Indent error pointer correctly in the presence of tabs.
Change-Id: I8e8aa9bcc70e9c4a0e951376f24db51aa51069b2
Reviewed-on: https://dart-review.googlesource.com/60426
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Peter von der Ahé <ahe@google.com>
diff --git a/pkg/front_end/lib/src/fasta/command_line_reporting.dart b/pkg/front_end/lib/src/fasta/command_line_reporting.dart
index c7f93ee..e682431 100644
--- a/pkg/front_end/lib/src/fasta/command_line_reporting.dart
+++ b/pkg/front_end/lib/src/fasta/command_line_reporting.dart
@@ -10,6 +10,10 @@
import 'dart:io' show exitCode;
+import 'dart:math' show min;
+
+import 'dart:typed_data' show Uint8List;
+
import 'package:kernel/ast.dart' show Location;
import 'colors.dart' show green, magenta, red;
@@ -27,6 +31,8 @@
import 'severity.dart' show Severity;
+import 'scanner/characters.dart' show $CARET, $SPACE, $TAB;
+
import 'util/relativize.dart' show relativizeUri;
const bool hideWarnings = false;
@@ -75,8 +81,21 @@
if (sourceLine == null) {
sourceLine = "";
} else if (sourceLine.isNotEmpty) {
- String indentation = " " * (location.column - 1);
- String pointer = indentation + ("^" * length);
+ // TODO(askesc): Much more could be done to indent properly in the
+ // presence of all sorts of unicode weirdness.
+ // This handling covers the common case of single-width characters
+ // indented with spaces and/or tabs, using no surrogates.
+ int indentLength = location.column - 1;
+ Uint8List indentation = new Uint8List(indentLength + length)
+ ..fillRange(0, indentLength, $SPACE)
+ ..fillRange(indentLength, indentLength + length, $CARET);
+ int lengthInSourceLine = min(indentation.length, sourceLine.length);
+ for (int i = 0; i < lengthInSourceLine; i++) {
+ if (sourceLine.codeUnitAt(i) == $TAB) {
+ indentation[i] = $TAB;
+ }
+ }
+ String pointer = new String.fromCharCodes(indentation);
if (pointer.length > sourceLine.length) {
// Truncate the carets to handle messages that span multiple lines.
int pointerLength = sourceLine.length;
diff --git a/pkg/front_end/testcases/tabs.dart b/pkg/front_end/testcases/tabs.dart
new file mode 100644
index 0000000..28a958f
--- /dev/null
+++ b/pkg/front_end/testcases/tabs.dart
@@ -0,0 +1,16 @@
+// Copyright (c) 2018, 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.
+
+// Test that error messages are indented correctly
+// in the presence of tabs.
+
+test() {
+ print(one);
+ print(two);
+ print(three);
+ print(four);
+ print(five);
+}
+
+main() {}
diff --git a/pkg/front_end/testcases/tabs.dart.direct.expect b/pkg/front_end/testcases/tabs.dart.direct.expect
new file mode 100644
index 0000000..b542e17
--- /dev/null
+++ b/pkg/front_end/testcases/tabs.dart.direct.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method test() → dynamic {
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#one, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#two, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#three, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#four, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#five, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/tabs.dart.direct.transformed.expect b/pkg/front_end/testcases/tabs.dart.direct.transformed.expect
new file mode 100644
index 0000000..b542e17
--- /dev/null
+++ b/pkg/front_end/testcases/tabs.dart.direct.transformed.expect
@@ -0,0 +1,12 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static method test() → dynamic {
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#one, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#two, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#three, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#four, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#five, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/tabs.dart.outline.expect b/pkg/front_end/testcases/tabs.dart.outline.expect
new file mode 100644
index 0000000..a29647d
--- /dev/null
+++ b/pkg/front_end/testcases/tabs.dart.outline.expect
@@ -0,0 +1,7 @@
+library;
+import self as self;
+
+static method test() → dynamic
+ ;
+static method main() → dynamic
+ ;
diff --git a/pkg/front_end/testcases/tabs.dart.strong.expect b/pkg/front_end/testcases/tabs.dart.strong.expect
new file mode 100644
index 0000000..83b1b86
--- /dev/null
+++ b/pkg/front_end/testcases/tabs.dart.strong.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/tabs.dart:9:8: Error: Getter not found: 'one'.
+\tprint(one);
+\t ^^^", "pkg/front_end/testcases/tabs.dart:10:9: Error: Getter not found: 'two'.
+\t\tprint(two);
+\t\t ^^^", "pkg/front_end/testcases/tabs.dart:11:11: Error: Getter not found: 'three'.
+\t\t print(three);
+\t\t ^^^^^", "pkg/front_end/testcases/tabs.dart:12:12: Error: Getter not found: 'four'.
+\t \tprint(four);
+\t \t ^^^^", "pkg/front_end/testcases/tabs.dart:13:14: Error: Getter not found: 'five'.
+\t \t print(five);
+\t \t ^^^^"]/* from null */;
+static method test() → dynamic {
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#one, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#two, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#three, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#four, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#five, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+}
+static method main() → dynamic {}
diff --git a/pkg/front_end/testcases/tabs.dart.strong.transformed.expect b/pkg/front_end/testcases/tabs.dart.strong.transformed.expect
new file mode 100644
index 0000000..83b1b86
--- /dev/null
+++ b/pkg/front_end/testcases/tabs.dart.strong.transformed.expect
@@ -0,0 +1,23 @@
+library;
+import self as self;
+import "dart:core" as core;
+
+static const field dynamic #errors = const <dynamic>["pkg/front_end/testcases/tabs.dart:9:8: Error: Getter not found: 'one'.
+\tprint(one);
+\t ^^^", "pkg/front_end/testcases/tabs.dart:10:9: Error: Getter not found: 'two'.
+\t\tprint(two);
+\t\t ^^^", "pkg/front_end/testcases/tabs.dart:11:11: Error: Getter not found: 'three'.
+\t\t print(three);
+\t\t ^^^^^", "pkg/front_end/testcases/tabs.dart:12:12: Error: Getter not found: 'four'.
+\t \tprint(four);
+\t \t ^^^^", "pkg/front_end/testcases/tabs.dart:13:14: Error: Getter not found: 'five'.
+\t \t print(five);
+\t \t ^^^^"]/* from null */;
+static method test() → dynamic {
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#one, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#two, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#three, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#four, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+ core::print(throw new core::NoSuchMethodError::withInvocation(null, new core::_InvocationMirror::_withType(#five, 33, const <core::Type>[], const <dynamic>[], core::Map::unmodifiable<core::Symbol, dynamic>(const <core::Symbol, dynamic>{}))));
+}
+static method main() → dynamic {}