| 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 e7b23eabf16033c2644321dc6abb60cc3aef99d4..3c4ea20ea84bd410a6d50cdec7260ac6c24dbbef 100644
 | 
| --- a/pkg/compiler/lib/src/io/source_information.dart
 | 
| +++ b/pkg/compiler/lib/src/io/source_information.dart
 | 
| @@ -8,11 +8,14 @@ import '../dart2jslib.dart' show SourceSpan, MessageKind;
 | 
|  import '../elements/elements.dart' show
 | 
|      AstElement,
 | 
|      LocalElement;
 | 
| -import '../scanner/scannerlib.dart' show Token;
 | 
| -import '../tree/tree.dart' show Node;
 | 
| -import '../js/js.dart' show JavaScriptNodeSourceInformation;
 | 
| +import '../tree/tree.dart' show Node, Send;
 | 
| +import '../js/js.dart' show
 | 
| +    JavaScriptNodeSourceInformation;
 | 
|  import 'source_file.dart';
 | 
|  
 | 
| +bool useNewSourceInfo =
 | 
| +    const bool.fromEnvironment('USE_NEW_SOURCE_INFO', defaultValue: false);
 | 
| +
 | 
|  /// Interface for passing source information, for instance for use in source
 | 
|  /// maps, through the backend.
 | 
|  abstract class SourceInformation extends JavaScriptNodeSourceInformation {
 | 
| @@ -26,14 +29,20 @@ abstract class SourceInformation extends JavaScriptNodeSourceInformation {
 | 
|  
 | 
|    /// The source location associated with the end of the JS node.
 | 
|    SourceLocation get endPosition => null;
 | 
| +
 | 
| +  /// All source locations associated with this source information.
 | 
| +  List<SourceLocation> get sourceLocations;
 | 
| +
 | 
| +  /// Return a short textual representation of the source location.
 | 
| +  String get shortText;
 | 
|  }
 | 
|  
 | 
| -/// Factory for creating [SourceInformationBuilder]s.
 | 
| -class SourceInformationFactory {
 | 
| -  const SourceInformationFactory();
 | 
| +/// Strategy for creating, processing and applying [SourceInformation].
 | 
| +class SourceInformationStrategy {
 | 
| +  const SourceInformationStrategy();
 | 
|  
 | 
|    /// Create a [SourceInformationBuilder] for [element].
 | 
| -  SourceInformationBuilder forContext(AstElement element) {
 | 
| +  SourceInformationBuilder createBuilderForContext(AstElement element) {
 | 
|      return const SourceInformationBuilder();
 | 
|    }
 | 
|  }
 | 
| @@ -43,9 +52,7 @@ class SourceInformationBuilder {
 | 
|    const SourceInformationBuilder();
 | 
|  
 | 
|    /// Create a [SourceInformationBuilder] for [element].
 | 
| -  SourceInformationBuilder forContext(AstElement element) {
 | 
| -    return this;
 | 
| -  }
 | 
| +  SourceInformationBuilder forContext(AstElement element) => this;
 | 
|  
 | 
|    /// Generate [SourceInformation] the declaration of [element].
 | 
|    SourceInformation buildDeclaration(AstElement element) => null;
 | 
| @@ -57,210 +64,32 @@ class SourceInformationBuilder {
 | 
|    /// Generate [SourceInformation] for the return [node].
 | 
|    SourceInformation buildReturn(Node node) => null;
 | 
|  
 | 
| +  /// Generate [SourceInformation] for an implicit return in [element].
 | 
| +  SourceInformation buildImplicitReturn(AstElement element) => 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 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;
 | 
| -    int end = endPosition == null ? begin : endPosition.offset;
 | 
| -    return new SourceSpan(uri, begin, end);
 | 
| -  }
 | 
| -
 | 
| -  int get hashCode {
 | 
| -    return 0x7FFFFFFF &
 | 
| -           (startPosition.hashCode * 17 + endPosition.hashCode * 19);
 | 
| -  }
 | 
| +  /// Generate [SourceInformation] for an invocation like `a.b()` where
 | 
| +  /// [receiver] points to the left-most part of the invocation, `a` in the
 | 
| +  /// example, and [call] points the 'name' of the call, `b` or `()` depending
 | 
| +  /// on whether `b` is a method or a field/getter.
 | 
| +  SourceInformation buildCall(Node receiver, Node call) => null;
 | 
|  
 | 
| -  bool operator ==(other) {
 | 
| -    if (identical(this, other)) return true;
 | 
| -    if (other is! StartEndSourceInformation) return false;
 | 
| -    return startPosition == other.startPosition &&
 | 
| -           endPosition == other.endPosition;
 | 
| -  }
 | 
| -
 | 
| -  // TODO(johnniwinther): Remove this method. Source information should be
 | 
| -  // computed based on the element by provided from statements and expressions.
 | 
| -  static StartEndSourceInformation computeSourceInformation(
 | 
| -      AstElement element) {
 | 
| -
 | 
| -    AstElement implementation = element.implementation;
 | 
| -    SourceFile sourceFile = implementation.compilationUnit.script.file;
 | 
| -    String name = computeElementNameForSourceMaps(element);
 | 
| -    Node node = implementation.node;
 | 
| -    Token beginToken;
 | 
| -    Token endToken;
 | 
| -    if (node == null) {
 | 
| -      // Synthesized node. Use the enclosing element for the location.
 | 
| -      beginToken = endToken = element.position;
 | 
| -    } else {
 | 
| -      beginToken = node.getBeginToken();
 | 
| -      endToken = node.getEndToken();
 | 
| -    }
 | 
| -    // TODO(podivilov): find the right sourceFile here and remove offset
 | 
| -    // checks below.
 | 
| -    SourceLocation sourcePosition, endSourcePosition;
 | 
| -    if (beginToken.charOffset < sourceFile.length) {
 | 
| -      sourcePosition =
 | 
| -          new OffsetSourceLocation(sourceFile, beginToken.charOffset, name);
 | 
| -    }
 | 
| -    if (endToken.charOffset < sourceFile.length) {
 | 
| -      endSourcePosition =
 | 
| -          new OffsetSourceLocation(sourceFile, endToken.charOffset, name);
 | 
| -    }
 | 
| -    return new StartEndSourceInformation(sourcePosition, endSourcePosition);
 | 
| -  }
 | 
| +  /// Generate [SourceInformation] for the if statement in [node].
 | 
| +  SourceInformation buildIf(Node node) => null;
 | 
|  
 | 
| -  String toString() {
 | 
| -    StringBuffer sb = new StringBuffer();
 | 
| -    sb.write('${startPosition.sourceUri}:');
 | 
| -    // Use 1-based line/column info to match usual dart tool output.
 | 
| -    sb.write('[${startPosition.line + 1},${startPosition.column + 1}]');
 | 
| -    if (endPosition != null) {
 | 
| -      sb.write('-[${endPosition.line + 1},${endPosition.column + 1}]');
 | 
| -    }
 | 
| -    return sb.toString();
 | 
| -  }
 | 
| -}
 | 
| +  /// Generate [SourceInformation] for the constructor invocation in [node].
 | 
| +  SourceInformation buildNew(Node node) => null;
 | 
|  
 | 
| -class StartEndSourceInformationFactory implements SourceInformationFactory {
 | 
| -  const StartEndSourceInformationFactory();
 | 
| +  /// Generate [SourceInformation] for the throw in [node].
 | 
| +  SourceInformation buildThrow(Node node) => null;
 | 
|  
 | 
| -  @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 = computeElementNameForSourceMaps(element);
 | 
| -
 | 
| -  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 extends SourceInformation {
 | 
| -  @override
 | 
| -  final SourceLocation startPosition;
 | 
| -
 | 
| -  @override
 | 
| -  final SourceLocation closingPosition;
 | 
| -
 | 
| -  PositionSourceInformation(this.startPosition,
 | 
| -                            [this.closingPosition]);
 | 
| -
 | 
| -  @override
 | 
| -  SourceSpan get sourceSpan {
 | 
| -    SourceLocation location =
 | 
| -        startPosition != null ? startPosition : closingPosition;
 | 
| -    Uri uri = location.sourceUri;
 | 
| -    int offset = location.offset;
 | 
| -    return new SourceSpan(uri, offset, offset);
 | 
| -  }
 | 
| -
 | 
| -  int get hashCode {
 | 
| -    return 0x7FFFFFFF &
 | 
| -           (startPosition.hashCode * 17 + closingPosition.hashCode * 19);
 | 
| -  }
 | 
| -
 | 
| -  bool operator ==(other) {
 | 
| -    if (identical(this, other)) return true;
 | 
| -    if (other is! PositionSourceInformation) return false;
 | 
| -    return startPosition == other.startPosition &&
 | 
| -           closingPosition == other.closingPosition;
 | 
| -  }
 | 
| -
 | 
| -  String toString() {
 | 
| -    StringBuffer sb = new StringBuffer();
 | 
| -    if (startPosition != null) {
 | 
| -      sb.write('${startPosition.sourceUri}:');
 | 
| -    } else {
 | 
| -      sb.write('${closingPosition.sourceUri}:');
 | 
| -    }
 | 
| -    // Use 1-based line/column info to match usual dart tool output.
 | 
| -    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();
 | 
| -  }
 | 
| +  /// Generate [SourceInformation] for the assignment in [node].
 | 
| +  SourceInformation buildAssignment(Node node) => null;
 | 
|  }
 | 
|  
 | 
|  /// A location in a source file.
 | 
| @@ -307,6 +136,11 @@ abstract class SourceLocation {
 | 
|             sourceName == other.sourceName;
 | 
|    }
 | 
|  
 | 
| +  String get shortText {
 | 
| +    // Use 1-based line/column info to match usual dart tool output.
 | 
| +    return '${sourceUri.pathSegments.last}:[${line + 1},${column + 1}]';
 | 
| +  }
 | 
| +
 | 
|    String toString() {
 | 
|      // Use 1-based line/column info to match usual dart tool output.
 | 
|      return '${sourceUri}:[${line + 1},${column + 1}]';
 | 
| @@ -320,65 +154,12 @@ class OffsetSourceLocation extends SourceLocation {
 | 
|    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 = computeElementNameForSourceMaps(element);
 | 
| -
 | 
| -  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));
 | 
| -    }
 | 
| +  String get shortText {
 | 
| +    return '${super.shortText}:$sourceName';
 | 
|    }
 | 
|  
 | 
| -  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);
 | 
| +  String toString() {
 | 
| +    return '${super.toString()}:$sourceName';
 | 
|    }
 | 
|  }
 | 
|  
 | 
| @@ -409,4 +190,4 @@ String computeElementNameForSourceMaps(AstElement element) {
 | 
|    } else {
 | 
|      return element.name;
 | 
|    }
 | 
| -}
 | 
| +}
 | 
| 
 |