| Index: pkg/compiler/lib/src/io/source_information.dart
|
| diff --git a/pkg/compiler/lib/src/io/source_information.dart b/pkg/compiler/lib/src/io/source_information.dart
|
| index 28e2191318bac9f9322014456828a9186dca963b..601256d2acc247629dde299635a654542a3631f2 100644
|
| --- a/pkg/compiler/lib/src/io/source_information.dart
|
| +++ b/pkg/compiler/lib/src/io/source_information.dart
|
| @@ -4,7 +4,7 @@
|
|
|
| library dart2js.source_information;
|
|
|
| -import '../dart2jslib.dart' show SourceSpan;
|
| +import '../dart2jslib.dart' show SourceSpan, MessageKind;
|
| import '../elements/elements.dart' show AstElement;
|
| import '../scanner/scannerlib.dart' show Token;
|
| import '../tree/tree.dart' show Node;
|
| @@ -17,20 +17,66 @@ abstract class SourceInformation extends JavaScriptNodeSourceInformation {
|
| SourceSpan get sourceSpan;
|
|
|
| /// The source location associated with the start of the JS node.
|
| - SourceLocation get startPosition;
|
| + SourceLocation get startPosition => null;
|
| +
|
| + /// The source location associated with the closing of the JS node.
|
| + SourceLocation get closingPosition => null;
|
|
|
| /// The source location associated with the end of the JS node.
|
| - SourceLocation get endPosition;
|
| + SourceLocation get endPosition => null;
|
| +}
|
| +
|
| +/// Factory for creating [SourceInformationBuilder]s.
|
| +class SourceInformationFactory {
|
| + const SourceInformationFactory();
|
| +
|
| + /// Create a [SourceInformationBuilder] for [element].
|
| + SourceInformationBuilder forContext(AstElement element) {
|
| + return const SourceInformationBuilder();
|
| + }
|
| +}
|
| +
|
| +/// Interface for generating [SourceInformation].
|
| +class SourceInformationBuilder {
|
| + const SourceInformationBuilder();
|
| +
|
| + /// Create a [SourceInformationBuilder] for [element].
|
| + SourceInformationBuilder forContext(AstElement element) {
|
| + return this;
|
| + }
|
| +
|
| + /// Generate [SourceInformation] the declaration of [element].
|
| + SourceInformation buildDeclaration(AstElement element) => null;
|
| +
|
| + /// Generate [SourceInformation] for the generic [node].
|
| + @deprecated
|
| + SourceInformation buildGeneric(Node node) => null;
|
| +
|
| + /// Generate [SourceInformation] for the return [node].
|
| + SourceInformation buildReturn(Node node) => null;
|
| +
|
| + /// Generate [SourceInformation] for the loop [node].
|
| + SourceInformation buildLoop(Node node) => null;
|
| +
|
| + /// Generate [SourceInformation] for the read access in [node].
|
| + SourceInformation buildGet(Node node) => null;
|
| +
|
| + /// Generate [SourceInformation] for the invocation in [node].
|
| + SourceInformation buildCall(Node node) => null;
|
| }
|
|
|
| /// Source information that contains start source position and optionally an
|
| /// end source position.
|
| -class StartEndSourceInformation implements SourceInformation {
|
| +class StartEndSourceInformation extends SourceInformation {
|
| + @override
|
| final SourceLocation startPosition;
|
| +
|
| + @override
|
| final SourceLocation endPosition;
|
|
|
| StartEndSourceInformation(this.startPosition, [this.endPosition]);
|
|
|
| + @override
|
| SourceSpan get sourceSpan {
|
| Uri uri = startPosition.sourceUri;
|
| int begin = startPosition.offset;
|
| @@ -39,9 +85,8 @@ class StartEndSourceInformation implements SourceInformation {
|
| }
|
|
|
| int get hashCode {
|
| - return (startPosition.hashCode * 17 +
|
| - endPosition.hashCode * 19)
|
| - & 0x7FFFFFFF;
|
| + return 0x7FFFFFFF &
|
| + (startPosition.hashCode * 17 + endPosition.hashCode * 19);
|
| }
|
|
|
| bool operator ==(other) {
|
| @@ -74,11 +119,11 @@ class StartEndSourceInformation implements SourceInformation {
|
| SourceLocation sourcePosition, endSourcePosition;
|
| if (beginToken.charOffset < sourceFile.length) {
|
| sourcePosition =
|
| - new TokenSourceLocation(sourceFile, beginToken, name);
|
| + new OffsetSourceLocation(sourceFile, beginToken.charOffset, name);
|
| }
|
| if (endToken.charOffset < sourceFile.length) {
|
| endSourcePosition =
|
| - new TokenSourceLocation(sourceFile, endToken, name);
|
| + new OffsetSourceLocation(sourceFile, endToken.charOffset, name);
|
| }
|
| return new StartEndSourceInformation(sourcePosition, endSourcePosition);
|
| }
|
| @@ -95,37 +140,123 @@ class StartEndSourceInformation implements SourceInformation {
|
| }
|
| }
|
|
|
| +class StartEndSourceInformationFactory implements SourceInformationFactory {
|
| + const StartEndSourceInformationFactory();
|
| +
|
| + @override
|
| + SourceInformationBuilder forContext(AstElement element) {
|
| + return new StartEndSourceInformationBuilder(element);
|
| + }
|
| +}
|
| +
|
| +/// [SourceInformationBuilder] that generates [PositionSourceInformation].
|
| +class StartEndSourceInformationBuilder extends SourceInformationBuilder {
|
| + final SourceFile sourceFile;
|
| + final String name;
|
| +
|
| + StartEndSourceInformationBuilder(AstElement element)
|
| + : sourceFile = element.compilationUnit.script.file,
|
| + name = element.name;
|
| +
|
| + SourceInformation buildDeclaration(AstElement element) {
|
| + return StartEndSourceInformation.computeSourceInformation(element);
|
| + }
|
| +
|
| + SourceLocation sourceFileLocationForToken(Token token) {
|
| + SourceLocation location =
|
| + new OffsetSourceLocation(sourceFile, token.charOffset, name);
|
| + checkValidSourceFileLocation(location, sourceFile, token.charOffset);
|
| + return location;
|
| + }
|
| +
|
| + void checkValidSourceFileLocation(
|
| + SourceLocation location, SourceFile sourceFile, int offset) {
|
| + if (!location.isValid) {
|
| + throw MessageKind.INVALID_SOURCE_FILE_LOCATION.message(
|
| + {'offset': offset,
|
| + 'fileName': sourceFile.filename,
|
| + 'length': sourceFile.length});
|
| + }
|
| + }
|
| +
|
| + @override
|
| + SourceInformation buildLoop(Node node) {
|
| + return new StartEndSourceInformation(
|
| + sourceFileLocationForToken(node.getBeginToken()),
|
| + sourceFileLocationForToken(node.getEndToken()));
|
| + }
|
| +
|
| + @override
|
| + SourceInformation buildGeneric(Node node) {
|
| + return new StartEndSourceInformation(
|
| + sourceFileLocationForToken(node.getBeginToken()));
|
| + }
|
| +
|
| + @override
|
| + SourceInformation buildReturn(Node node) => buildGeneric(node);
|
| +
|
| + @override
|
| + SourceInformation buildGet(Node node) => buildGeneric(node);
|
| +
|
| + @override
|
| + SourceInformation buildCall(Node node) => buildGeneric(node);
|
| +
|
| + @override
|
| + SourceInformationBuilder forContext(
|
| + AstElement element, {SourceInformation sourceInformation}) {
|
| + return new StartEndSourceInformationBuilder(element);
|
| + }
|
| +}
|
| +
|
| /// [SourceInformation] that consists of an offset position into the source
|
| /// code.
|
| -class PositionSourceInformation implements SourceInformation {
|
| - final SourceLocation sourcePosition;
|
| +class PositionSourceInformation extends SourceInformation {
|
| + @override
|
| + final SourceLocation startPosition;
|
|
|
| - PositionSourceInformation(this.sourcePosition);
|
| + @override
|
| + final SourceLocation closingPosition;
|
|
|
| - SourceLocation get startPosition => sourcePosition;
|
| - SourceLocation get endPosition => null;
|
| + PositionSourceInformation(this.startPosition,
|
| + [this.closingPosition]);
|
|
|
| + @override
|
| SourceSpan get sourceSpan {
|
| - Uri uri = sourcePosition.sourceUri;
|
| - int offset = sourcePosition.offset;
|
| + SourceLocation location =
|
| + startPosition != null ? startPosition : closingPosition;
|
| + Uri uri = location.sourceUri;
|
| + int offset = location.offset;
|
| return new SourceSpan(uri, offset, offset);
|
| }
|
|
|
| int get hashCode {
|
| - return sourcePosition.hashCode * 17 & 0x7FFFFFFF;
|
| + return 0x7FFFFFFF &
|
| + (startPosition.hashCode * 17 + closingPosition.hashCode * 19);
|
| }
|
|
|
| bool operator ==(other) {
|
| if (identical(this, other)) return true;
|
| if (other is! PositionSourceInformation) return false;
|
| - return sourcePosition == other.sourcePosition;
|
| + return startPosition == other.startPosition &&
|
| + closingPosition == other.closingPosition;
|
| }
|
|
|
| String toString() {
|
| StringBuffer sb = new StringBuffer();
|
| - sb.write('${sourcePosition.sourceUri}:');
|
| + if (startPosition != null) {
|
| + sb.write('${startPosition.sourceUri}:');
|
| + } else {
|
| + sb.write('${closingPosition.sourceUri}:');
|
| + }
|
| // Use 1-based line/column info to match usual dart tool output.
|
| - sb.write('[${sourcePosition.line + 1},${sourcePosition.column + 1}]');
|
| + if (startPosition != null) {
|
| + sb.write('[${startPosition.line + 1},'
|
| + '${startPosition.column + 1}]');
|
| + }
|
| + if (closingPosition != null) {
|
| + sb.write('-[${closingPosition.line + 1},'
|
| + '${closingPosition.column + 1}]');
|
| + }
|
| return sb.toString();
|
| }
|
| }
|
| @@ -180,17 +311,71 @@ abstract class SourceLocation {
|
| }
|
| }
|
|
|
| -class TokenSourceLocation extends SourceLocation {
|
| - final Token token;
|
| +class OffsetSourceLocation extends SourceLocation {
|
| + final int offset;
|
| final String sourceName;
|
|
|
| - TokenSourceLocation(SourceFile sourceFile, this.token, this.sourceName)
|
| - : super(sourceFile);
|
| -
|
| - @override
|
| - int get offset => token.charOffset;
|
| + OffsetSourceLocation(SourceFile sourceFile, this.offset, this.sourceName)
|
| + : super(sourceFile);
|
|
|
| String toString() {
|
| return '${super.toString()}:$sourceName';
|
| }
|
| }
|
| +
|
| +class PositionSourceInformationFactory implements SourceInformationFactory {
|
| + const PositionSourceInformationFactory();
|
| +
|
| + @override
|
| + SourceInformationBuilder forContext(AstElement element) {
|
| + return new PositionSourceInformationBuilder(element);
|
| + }
|
| +}
|
| +
|
| +/// [SourceInformationBuilder] that generates [PositionSourceInformation].
|
| +class PositionSourceInformationBuilder implements SourceInformationBuilder {
|
| + final SourceFile sourceFile;
|
| + final String name;
|
| +
|
| + PositionSourceInformationBuilder(AstElement element)
|
| + : sourceFile = element.implementation.compilationUnit.script.file,
|
| + name = element.name;
|
| +
|
| + SourceInformation buildDeclaration(AstElement element) {
|
| + if (element.isSynthesized) {
|
| + return new PositionSourceInformation(
|
| + new OffsetSourceLocation(
|
| + sourceFile, element.position.charOffset, name));
|
| + } else {
|
| + return new PositionSourceInformation(
|
| + null,
|
| + new OffsetSourceLocation(sourceFile,
|
| + element.resolvedAst.node.getEndToken().charOffset, name));
|
| + }
|
| + }
|
| +
|
| + SourceInformation buildBegin(Node node) {
|
| + return new PositionSourceInformation(new OffsetSourceLocation(
|
| + sourceFile, node.getBeginToken().charOffset, name));
|
| + }
|
| +
|
| + @override
|
| + SourceInformation buildGeneric(Node node) => buildBegin(node);
|
| +
|
| + @override
|
| + SourceInformation buildReturn(Node node) => buildBegin(node);
|
| +
|
| + @override
|
| + SourceInformation buildLoop(Node node) => buildBegin(node);
|
| +
|
| + @override
|
| + SourceInformation buildGet(Node node) => buildBegin(node);
|
| +
|
| + @override
|
| + SourceInformation buildCall(Node node) => buildBegin(node);
|
| +
|
| + @override
|
| + SourceInformationBuilder forContext(AstElement element) {
|
| + return new PositionSourceInformationBuilder(element);
|
| + }
|
| +}
|
|
|