Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file |
| 2 // for details. All rights reserved. Use of this source code is governed by a | 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. | 3 // BSD-style license that can be found in the LICENSE file. |
| 4 | 4 |
| 5 library dart2js.source_information; | 5 library dart2js.source_information; |
| 6 | 6 |
| 7 import '../dart2jslib.dart' show SourceSpan; | 7 import '../dart2jslib.dart' show SourceSpan, MessageKind; |
| 8 import '../elements/elements.dart' show AstElement; | 8 import '../elements/elements.dart' show AstElement; |
| 9 import '../scanner/scannerlib.dart' show Token; | 9 import '../scanner/scannerlib.dart' show Token; |
| 10 import '../tree/tree.dart' show Node; | 10 import '../tree/tree.dart' show Node; |
| 11 import '../js/js.dart' show JavaScriptNodeSourceInformation; | 11 import '../js/js.dart' show JavaScriptNodeSourceInformation; |
| 12 import 'source_file.dart'; | 12 import 'source_file.dart'; |
| 13 | 13 |
| 14 /// Interface for passing source information, for instance for use in source | 14 /// Interface for passing source information, for instance for use in source |
| 15 /// maps, through the backend. | 15 /// maps, through the backend. |
| 16 abstract class SourceInformation extends JavaScriptNodeSourceInformation { | 16 abstract class SourceInformation extends JavaScriptNodeSourceInformation { |
| 17 SourceSpan get sourceSpan; | 17 SourceSpan get sourceSpan; |
| 18 | 18 |
| 19 /// The source location associated with the start of the JS node. | 19 /// The source location associated with the start of the JS node. |
| 20 SourceLocation get startPosition; | 20 SourceLocation get startPosition => null; |
| 21 | |
| 22 /// The source location associated with the closing of the JS node. | |
| 23 SourceLocation get closingPosition => null; | |
| 21 | 24 |
| 22 /// The source location associated with the end of the JS node. | 25 /// The source location associated with the end of the JS node. |
| 23 SourceLocation get endPosition; | 26 SourceLocation get endPosition => null; |
| 27 } | |
| 28 | |
| 29 /// Factory for creating [SourceInformationBuilder]s. | |
| 30 class SourceInformationFactory { | |
| 31 const SourceInformationFactory(); | |
| 32 | |
| 33 /// Create a [SourceInformationBuilder] for [element]. | |
| 34 SourceInformationBuilder forContext(AstElement element) { | |
| 35 return const SourceInformationBuilder(); | |
| 36 } | |
| 37 } | |
| 38 | |
| 39 /// Interface for generating [SourceInformation]. | |
| 40 class SourceInformationBuilder { | |
| 41 const SourceInformationBuilder(); | |
| 42 | |
| 43 /// Create a [SourceInformationBuilder] for [element]. | |
| 44 SourceInformationBuilder forContext(AstElement element) { | |
| 45 return this; | |
| 46 } | |
| 47 | |
| 48 /// Generate [SourceInformation] the declaration of [element]. | |
| 49 SourceInformation buildDeclaration(AstElement element) => null; | |
| 50 | |
| 51 /// Generate [SourceInformation] for the generic [node]. | |
| 52 @deprecated | |
| 53 SourceInformation buildGeneric(Node node) => null; | |
| 54 | |
| 55 /// Generate [SourceInformation] for the return [node]. | |
| 56 SourceInformation buildReturn(Node node) => null; | |
| 57 | |
| 58 /// Generate [SourceInformation] for the loop [node]. | |
| 59 SourceInformation buildLoop(Node node) => null; | |
| 60 | |
| 61 /// Generate [SourceInformation] for the read access in [node]. | |
| 62 SourceInformation buildGet(Node node) => null; | |
| 63 | |
| 64 /// Generate [SourceInformation] for the invocation in [node]. | |
| 65 SourceInformation buildCall(Node node) => null; | |
| 24 } | 66 } |
| 25 | 67 |
| 26 /// Source information that contains start source position and optionally an | 68 /// Source information that contains start source position and optionally an |
| 27 /// end source position. | 69 /// end source position. |
| 28 class StartEndSourceInformation implements SourceInformation { | 70 class StartEndSourceInformation extends SourceInformation { |
| 71 @override | |
| 29 final SourceLocation startPosition; | 72 final SourceLocation startPosition; |
| 73 | |
| 74 @override | |
| 30 final SourceLocation endPosition; | 75 final SourceLocation endPosition; |
| 31 | 76 |
| 32 StartEndSourceInformation(this.startPosition, [this.endPosition]); | 77 StartEndSourceInformation(this.startPosition, [this.endPosition]); |
| 33 | 78 |
| 79 @override | |
| 34 SourceSpan get sourceSpan { | 80 SourceSpan get sourceSpan { |
| 35 Uri uri = startPosition.sourceUri; | 81 Uri uri = startPosition.sourceUri; |
| 36 int begin = startPosition.offset; | 82 int begin = startPosition.offset; |
| 37 int end = endPosition == null ? begin : endPosition.offset; | 83 int end = endPosition == null ? begin : endPosition.offset; |
| 38 return new SourceSpan(uri, begin, end); | 84 return new SourceSpan(uri, begin, end); |
| 39 } | 85 } |
| 40 | 86 |
| 41 int get hashCode { | 87 int get hashCode { |
| 42 return (startPosition.hashCode * 17 + | 88 return 0x7FFFFFFF & |
| 43 endPosition.hashCode * 19) | 89 (startPosition.hashCode * 17 + endPosition.hashCode * 19); |
| 44 & 0x7FFFFFFF; | |
| 45 } | 90 } |
| 46 | 91 |
| 47 bool operator ==(other) { | 92 bool operator ==(other) { |
| 48 if (identical(this, other)) return true; | 93 if (identical(this, other)) return true; |
| 49 if (other is! StartEndSourceInformation) return false; | 94 if (other is! StartEndSourceInformation) return false; |
| 50 return startPosition == other.startPosition && | 95 return startPosition == other.startPosition && |
| 51 endPosition == other.endPosition; | 96 endPosition == other.endPosition; |
| 52 } | 97 } |
| 53 | 98 |
| 54 // TODO(johnniwinther): Remove this method. Source information should be | 99 // TODO(johnniwinther): Remove this method. Source information should be |
| (...skipping 12 matching lines...) Expand all Loading... | |
| 67 beginToken = endToken = element.position; | 112 beginToken = endToken = element.position; |
| 68 } else { | 113 } else { |
| 69 beginToken = node.getBeginToken(); | 114 beginToken = node.getBeginToken(); |
| 70 endToken = node.getEndToken(); | 115 endToken = node.getEndToken(); |
| 71 } | 116 } |
| 72 // TODO(podivilov): find the right sourceFile here and remove offset | 117 // TODO(podivilov): find the right sourceFile here and remove offset |
| 73 // checks below. | 118 // checks below. |
| 74 SourceLocation sourcePosition, endSourcePosition; | 119 SourceLocation sourcePosition, endSourcePosition; |
| 75 if (beginToken.charOffset < sourceFile.length) { | 120 if (beginToken.charOffset < sourceFile.length) { |
| 76 sourcePosition = | 121 sourcePosition = |
| 77 new TokenSourceLocation(sourceFile, beginToken, name); | 122 new OffsetSourceLocation(sourceFile, beginToken.charOffset, name); |
| 78 } | 123 } |
| 79 if (endToken.charOffset < sourceFile.length) { | 124 if (endToken.charOffset < sourceFile.length) { |
| 80 endSourcePosition = | 125 endSourcePosition = |
| 81 new TokenSourceLocation(sourceFile, endToken, name); | 126 new OffsetSourceLocation(sourceFile, endToken.charOffset, name); |
| 82 } | 127 } |
| 83 return new StartEndSourceInformation(sourcePosition, endSourcePosition); | 128 return new StartEndSourceInformation(sourcePosition, endSourcePosition); |
| 84 } | 129 } |
| 85 | 130 |
| 86 String toString() { | 131 String toString() { |
| 87 StringBuffer sb = new StringBuffer(); | 132 StringBuffer sb = new StringBuffer(); |
| 88 sb.write('${startPosition.sourceUri}:'); | 133 sb.write('${startPosition.sourceUri}:'); |
| 89 // Use 1-based line/column info to match usual dart tool output. | 134 // Use 1-based line/column info to match usual dart tool output. |
| 90 sb.write('[${startPosition.line + 1},${startPosition.column + 1}]'); | 135 sb.write('[${startPosition.line + 1},${startPosition.column + 1}]'); |
| 91 if (endPosition != null) { | 136 if (endPosition != null) { |
| 92 sb.write('-[${endPosition.line + 1},${endPosition.column + 1}]'); | 137 sb.write('-[${endPosition.line + 1},${endPosition.column + 1}]'); |
| 93 } | 138 } |
| 94 return sb.toString(); | 139 return sb.toString(); |
| 95 } | 140 } |
| 96 } | 141 } |
| 97 | 142 |
| 143 class StartEndSourceInformationFactory implements SourceInformationFactory { | |
| 144 const StartEndSourceInformationFactory(); | |
| 145 | |
| 146 @override | |
| 147 SourceInformationBuilder forContext(AstElement element) { | |
| 148 return new StartEndSourceInformationBuilder(element); | |
| 149 } | |
| 150 } | |
| 151 | |
| 152 /// [SourceInformationBuilder] that generates [PositionSourceInformation]. | |
| 153 class StartEndSourceInformationBuilder extends SourceInformationBuilder { | |
| 154 final SourceFile sourceFile; | |
| 155 final String name; | |
| 156 | |
| 157 StartEndSourceInformationBuilder(AstElement element) | |
| 158 : sourceFile = element.compilationUnit.script.file, | |
| 159 name = element.name; | |
| 160 | |
| 161 SourceInformation buildDeclaration(AstElement element) { | |
| 162 return StartEndSourceInformation.computeSourceInformation(element); | |
| 163 } | |
| 164 | |
| 165 SourceLocation sourceFileLocationForToken(Token token) { | |
| 166 SourceLocation location = | |
| 167 new OffsetSourceLocation(sourceFile, token.charOffset, name); | |
| 168 checkValidSourceFileLocation(location, sourceFile, token.charOffset); | |
| 169 return location; | |
| 170 } | |
| 171 | |
| 172 void checkValidSourceFileLocation( | |
| 173 SourceLocation location, SourceFile sourceFile, int offset) { | |
| 174 if (!location.isValid) { | |
| 175 throw MessageKind.INVALID_SOURCE_FILE_LOCATION.message( | |
| 176 {'offset': offset, | |
| 177 'fileName': sourceFile.filename, | |
| 178 'length': sourceFile.length}); | |
| 179 } | |
| 180 } | |
| 181 | |
| 182 @override | |
| 183 SourceInformation buildLoop(Node node) { | |
| 184 return new StartEndSourceInformation( | |
| 185 sourceFileLocationForToken(node.getBeginToken()), | |
| 186 sourceFileLocationForToken(node.getEndToken())); | |
| 187 } | |
| 188 | |
| 189 @override | |
| 190 SourceInformation buildGeneric(Node node) { | |
| 191 return new StartEndSourceInformation( | |
| 192 sourceFileLocationForToken(node.getBeginToken())); | |
| 193 } | |
| 194 | |
| 195 @override | |
| 196 SourceInformation buildReturn(Node node) => buildGeneric(node); | |
| 197 | |
| 198 @override | |
| 199 SourceInformation buildGet(Node node) => buildGeneric(node); | |
| 200 | |
| 201 @override | |
| 202 SourceInformation buildCall(Node node) => buildGeneric(node); | |
| 203 | |
| 204 @override | |
| 205 SourceInformationBuilder forContext( | |
| 206 AstElement element, {SourceInformation sourceInformation}) { | |
| 207 return new StartEndSourceInformationBuilder(element); | |
| 208 } | |
| 209 } | |
| 210 | |
| 98 /// [SourceInformation] that consists of an offset position into the source | 211 /// [SourceInformation] that consists of an offset position into the source |
| 99 /// code. | 212 /// code. |
| 100 class PositionSourceInformation implements SourceInformation { | 213 class PositionSourceInformation extends SourceInformation { |
| 101 final SourceLocation sourcePosition; | 214 @override |
| 215 final SourceLocation startPosition; | |
| 102 | 216 |
| 103 PositionSourceInformation(this.sourcePosition); | 217 @override |
| 218 final SourceLocation closingPosition; | |
| 104 | 219 |
| 105 SourceLocation get startPosition => sourcePosition; | 220 PositionSourceInformation(this.startPosition, |
| 106 SourceLocation get endPosition => null; | 221 [this.closingPosition]); |
| 107 | 222 |
| 223 @override | |
| 108 SourceSpan get sourceSpan { | 224 SourceSpan get sourceSpan { |
| 109 Uri uri = sourcePosition.sourceUri; | 225 SourceLocation location = |
| 110 int offset = sourcePosition.offset; | 226 startPosition != null ? startPosition : closingPosition; |
| 227 Uri uri = location.sourceUri; | |
| 228 int offset = location.offset; | |
| 111 return new SourceSpan(uri, offset, offset); | 229 return new SourceSpan(uri, offset, offset); |
| 112 } | 230 } |
| 113 | 231 |
| 114 int get hashCode { | 232 int get hashCode { |
| 115 return sourcePosition.hashCode * 17 & 0x7FFFFFFF; | 233 return 0x7FFFFFFF & |
| 234 (startPosition.hashCode * 17 + closingPosition.hashCode * 19); | |
| 116 } | 235 } |
| 117 | 236 |
| 118 bool operator ==(other) { | 237 bool operator ==(other) { |
| 119 if (identical(this, other)) return true; | 238 if (identical(this, other)) return true; |
| 120 if (other is! PositionSourceInformation) return false; | 239 if (other is! PositionSourceInformation) return false; |
| 121 return sourcePosition == other.sourcePosition; | 240 return startPosition == other.startPosition && |
| 241 closingPosition == other.closingPosition; | |
| 122 } | 242 } |
| 123 | 243 |
| 124 String toString() { | 244 String toString() { |
| 125 StringBuffer sb = new StringBuffer(); | 245 StringBuffer sb = new StringBuffer(); |
| 126 sb.write('${sourcePosition.sourceUri}:'); | 246 if (startPosition != null) { |
| 247 sb.write('${startPosition.sourceUri}:'); | |
| 248 } else { | |
| 249 sb.write('${closingPosition.sourceUri}:'); | |
| 250 } | |
| 127 // Use 1-based line/column info to match usual dart tool output. | 251 // Use 1-based line/column info to match usual dart tool output. |
| 128 sb.write('[${sourcePosition.line + 1},${sourcePosition.column + 1}]'); | 252 if (startPosition != null) { |
| 253 sb.write('[${startPosition.line + 1},' | |
| 254 '${startPosition.column + 1}]'); | |
| 255 } | |
| 256 if (closingPosition != null) { | |
| 257 sb.write('-[${closingPosition.line + 1},' | |
| 258 '${closingPosition.column + 1}]'); | |
| 259 } | |
| 129 return sb.toString(); | 260 return sb.toString(); |
| 130 } | 261 } |
| 131 } | 262 } |
| 132 | 263 |
| 133 /// A location in a source file. | 264 /// A location in a source file. |
| 134 abstract class SourceLocation { | 265 abstract class SourceLocation { |
| 135 final SourceFile _sourceFile; | 266 final SourceFile _sourceFile; |
| 136 int _line; | 267 int _line; |
| 137 | 268 |
| 138 SourceLocation(this._sourceFile) { | 269 SourceLocation(this._sourceFile) { |
| (...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 173 offset == other.offset && | 304 offset == other.offset && |
| 174 sourceName == other.sourceName; | 305 sourceName == other.sourceName; |
| 175 } | 306 } |
| 176 | 307 |
| 177 String toString() { | 308 String toString() { |
| 178 // Use 1-based line/column info to match usual dart tool output. | 309 // Use 1-based line/column info to match usual dart tool output. |
| 179 return '${sourceUri}:[${line + 1},${column + 1}]'; | 310 return '${sourceUri}:[${line + 1},${column + 1}]'; |
| 180 } | 311 } |
| 181 } | 312 } |
| 182 | 313 |
| 183 class TokenSourceLocation extends SourceLocation { | 314 class OffsetSourceLocation extends SourceLocation { |
| 184 final Token token; | 315 final int offset; |
| 185 final String sourceName; | 316 final String sourceName; |
| 186 | 317 |
| 187 TokenSourceLocation(SourceFile sourceFile, this.token, this.sourceName) | 318 OffsetSourceLocation(SourceFile sourceFile, this.offset, this.sourceName) |
| 188 : super(sourceFile); | 319 : super(sourceFile); |
|
floitsch
2015/04/21 11:31:53
indent++
Johnni Winther
2015/04/21 12:07:01
Done.
| |
| 189 | 320 |
| 190 @override | |
| 191 int get offset => token.charOffset; | |
| 192 | 321 |
| 193 String toString() { | 322 String toString() { |
| 194 return '${super.toString()}:$sourceName'; | 323 return '${super.toString()}:$sourceName'; |
| 195 } | 324 } |
| 196 } | 325 } |
| 326 | |
| 327 class PositionSourceInformationFactory implements SourceInformationFactory { | |
| 328 const PositionSourceInformationFactory(); | |
| 329 | |
| 330 @override | |
| 331 SourceInformationBuilder forContext(AstElement element) { | |
| 332 return new PositionSourceInformationBuilder(element); | |
| 333 } | |
| 334 } | |
| 335 | |
| 336 /// [SourceInformationBuilder] that generates [PositionSourceInformation]. | |
| 337 class PositionSourceInformationBuilder implements SourceInformationBuilder { | |
| 338 final SourceFile sourceFile; | |
| 339 final String name; | |
| 340 | |
| 341 PositionSourceInformationBuilder(AstElement element) | |
| 342 : sourceFile = element.implementation.compilationUnit.script.file, | |
| 343 name = element.name; | |
| 344 | |
| 345 SourceInformation buildDeclaration(AstElement element) { | |
| 346 if (element.isSynthesized) { | |
| 347 return new PositionSourceInformation( | |
| 348 new OffsetSourceLocation( | |
| 349 sourceFile, element.position.charOffset, name)); | |
| 350 } else { | |
| 351 return new PositionSourceInformation( | |
| 352 null, | |
| 353 new OffsetSourceLocation(sourceFile, | |
| 354 element.resolvedAst.node.getEndToken().charOffset, name)); | |
| 355 } | |
| 356 } | |
| 357 | |
| 358 SourceInformation buildBegin(Node node) { | |
| 359 return new PositionSourceInformation(new OffsetSourceLocation( | |
| 360 sourceFile, node.getBeginToken().charOffset, name)); | |
| 361 } | |
| 362 | |
| 363 @override | |
| 364 SourceInformation buildGeneric(Node node) => buildBegin(node); | |
| 365 | |
| 366 @override | |
| 367 SourceInformation buildReturn(Node node) => buildBegin(node); | |
| 368 | |
| 369 @override | |
| 370 SourceInformation buildLoop(Node node) => buildBegin(node); | |
| 371 | |
| 372 @override | |
| 373 SourceInformation buildGet(Node node) => buildBegin(node); | |
| 374 | |
| 375 @override | |
| 376 SourceInformation buildCall(Node node) => buildBegin(node); | |
| 377 | |
| 378 @override | |
| 379 SourceInformationBuilder forContext(AstElement element) { | |
| 380 return new PositionSourceInformationBuilder(element); | |
| 381 } | |
| 382 } | |
| OLD | NEW |