Line data Source code
1 : // Copyright (c) 2014, the Dart project authors. Please see the AUTHORS file 2 : // for details. All rights reserved. Use of this source code is governed by a 3 : // BSD-style license that can be found in the LICENSE file. 4 : 5 : import 'span.dart'; 6 : 7 : // TODO(nweiz): Use SourceLocationMixin once we decide to cut a release with 8 : // breaking changes. See SourceLocationMixin for details. 9 : 10 : /// A class that describes a single location within a source file. 11 : /// 12 : /// This class should not be extended. Instead, [SourceLocationBase] should be 13 : /// extended instead. 14 : class SourceLocation implements Comparable<SourceLocation> { 15 : /// URL of the source containing this location. 16 : /// 17 : /// This may be null, indicating that the source URL is unknown or 18 : /// unavailable. 19 : final Uri? sourceUrl; 20 : 21 : /// The 0-based offset of this location in the source. 22 : final int offset; 23 : 24 : /// The 0-based line of this location in the source. 25 : final int line; 26 : 27 : /// The 0-based column of this location in the source 28 : final int column; 29 : 30 : /// Returns a representation of this location in the `source:line:column` 31 : /// format used by text editors. 32 : /// 33 : /// This prints 1-based lines and columns. 34 0 : String get toolString { 35 0 : final source = sourceUrl ?? 'unknown source'; 36 0 : return '$source:${line + 1}:${column + 1}'; 37 : } 38 : 39 : /// Creates a new location indicating [offset] within [sourceUrl]. 40 : /// 41 : /// [line] and [column] default to assuming the source is a single line. This 42 : /// means that [line] defaults to 0 and [column] defaults to [offset]. 43 : /// 44 : /// [sourceUrl] may be either a [String], a [Uri], or `null`. 45 0 : SourceLocation(this.offset, {sourceUrl, int? line, int? column}) 46 : : sourceUrl = 47 0 : sourceUrl is String ? Uri.parse(sourceUrl) : sourceUrl as Uri?, 48 : line = line ?? 0, 49 : column = column ?? offset { 50 0 : if (offset < 0) { 51 0 : throw RangeError('Offset may not be negative, was $offset.'); 52 0 : } else if (line != null && line < 0) { 53 0 : throw RangeError('Line may not be negative, was $line.'); 54 0 : } else if (column != null && column < 0) { 55 0 : throw RangeError('Column may not be negative, was $column.'); 56 : } 57 : } 58 : 59 : /// Returns the distance in characters between `this` and [other]. 60 : /// 61 : /// This always returns a non-negative value. 62 0 : int distance(SourceLocation other) { 63 0 : if (sourceUrl != other.sourceUrl) { 64 0 : throw ArgumentError('Source URLs \"$sourceUrl\" and ' 65 0 : "\"${other.sourceUrl}\" don't match."); 66 : } 67 0 : return (offset - other.offset).abs(); 68 : } 69 : 70 : /// Returns a span that covers only a single point: this location. 71 0 : SourceSpan pointSpan() => SourceSpan(this, this, ''); 72 : 73 : /// Compares two locations. 74 : /// 75 : /// [other] must have the same source URL as `this`. 76 0 : @override 77 : int compareTo(SourceLocation other) { 78 0 : if (sourceUrl != other.sourceUrl) { 79 0 : throw ArgumentError('Source URLs \"$sourceUrl\" and ' 80 0 : "\"${other.sourceUrl}\" don't match."); 81 : } 82 0 : return offset - other.offset; 83 : } 84 : 85 0 : @override 86 : bool operator ==(other) => 87 0 : other is SourceLocation && 88 0 : sourceUrl == other.sourceUrl && 89 0 : offset == other.offset; 90 : 91 0 : @override 92 0 : int get hashCode => (sourceUrl?.hashCode ?? 0) + offset; 93 : 94 0 : @override 95 0 : String toString() => '<$runtimeType: $offset $toolString>'; 96 : } 97 : 98 : /// A base class for source locations with [offset], [line], and [column] known 99 : /// at construction time. 100 : class SourceLocationBase extends SourceLocation { 101 0 : SourceLocationBase(int offset, {sourceUrl, int? line, int? column}) 102 0 : : super(offset, sourceUrl: sourceUrl, line: line, column: column); 103 : }