Chromium Code Reviews| 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..f578c5d16c7901eb4b2b1a0a7c7e288bb044b6fd 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,72 @@ 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) |
| + OffsetSourceLocation(SourceFile sourceFile, this.offset, this.sourceName) |
| : super(sourceFile); |
|
floitsch
2015/04/21 11:31:53
indent++
Johnni Winther
2015/04/21 12:07:01
Done.
|
| - @override |
| - int get offset => token.charOffset; |
| 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); |
| + } |
| +} |