| Index: pkg/front_end/lib/src/fasta/source/outline_builder.dart
 | 
| diff --git a/pkg/front_end/lib/src/fasta/source/outline_builder.dart b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
 | 
| index f14505d31162da0c070381b73937e3b54d16d987..88acba4b52b609ae9af5c009b072948bc9f30e02 100644
 | 
| --- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
 | 
| +++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
 | 
| @@ -8,6 +8,8 @@ import 'package:kernel/ast.dart' show AsyncMarker, ProcedureKind;
 | 
|  
 | 
|  import '../parser/parser.dart' show FormalParameterType, optional;
 | 
|  
 | 
| +import '../parser/identifier_context.dart' show IdentifierContext;
 | 
| +
 | 
|  import '../scanner/token.dart' show Token;
 | 
|  
 | 
|  import '../util/link.dart' show Link;
 | 
| @@ -74,20 +76,36 @@ class OutlineBuilder extends UnhandledListener {
 | 
|    Uri get uri => library.fileUri;
 | 
|  
 | 
|    @override
 | 
| +  int popCharOffset() => pop();
 | 
| +
 | 
| +  List<String> popIdentifierList(int count) {
 | 
| +    if (count == 0) return null;
 | 
| +    List<String> list = new List<String>.filled(count, null, growable: true);
 | 
| +    for (int i = count - 1; i >= 0; i--) {
 | 
| +      popCharOffset();
 | 
| +      list[i] = pop();
 | 
| +    }
 | 
| +    return list;
 | 
| +  }
 | 
| +
 | 
| +  @override
 | 
|    void endMetadata(Token beginToken, Token periodBeforeName, Token endToken) {
 | 
|      debugEvent("Metadata");
 | 
|      List arguments = pop();
 | 
| +    popIfNotNull(periodBeforeName); // charOffset.
 | 
|      String postfix = popIfNotNull(periodBeforeName);
 | 
|      List<TypeBuilder> typeArguments = pop();
 | 
|      if (arguments == null) {
 | 
| +      int charOffset = pop();
 | 
|        String expression = pop();
 | 
|        push(new MetadataBuilder.fromExpression(
 | 
| -          expression, postfix, library, beginToken.charOffset));
 | 
| +          expression, postfix, library, charOffset));
 | 
|      } else {
 | 
| +      int charOffset = pop();
 | 
|        String typeName = pop();
 | 
|        push(new MetadataBuilder.fromConstructor(
 | 
|            library.addConstructorReference(
 | 
| -              typeName, typeArguments, postfix, beginToken.next.charOffset),
 | 
| +              typeName, typeArguments, postfix, charOffset),
 | 
|            arguments,
 | 
|            library,
 | 
|            beginToken.charOffset));
 | 
| @@ -119,6 +137,7 @@ class OutlineBuilder extends UnhandledListener {
 | 
|      debugEvent("Export");
 | 
|      List<Combinator> combinators = pop();
 | 
|      Unhandled conditionalUris = pop();
 | 
| +    popCharOffset();
 | 
|      String uri = pop();
 | 
|      List<MetadataBuilder> metadata = pop();
 | 
|      if (uri != null) {
 | 
| @@ -133,20 +152,15 @@ class OutlineBuilder extends UnhandledListener {
 | 
|        Token semicolon) {
 | 
|      debugEvent("endImport");
 | 
|      List<Combinator> combinators = pop();
 | 
| +    int prefixOffset = popIfNotNull(asKeyword) ?? -1;
 | 
|      String prefix = popIfNotNull(asKeyword);
 | 
|      Unhandled conditionalUris = pop();
 | 
| +    popCharOffset();
 | 
|      String uri = pop();
 | 
|      List<MetadataBuilder> metadata = pop();
 | 
|      if (uri != null) {
 | 
| -      library.addImport(
 | 
| -          metadata,
 | 
| -          uri,
 | 
| -          conditionalUris,
 | 
| -          prefix,
 | 
| -          combinators,
 | 
| -          deferredKeyword != null,
 | 
| -          importKeyword.charOffset,
 | 
| -          asKeyword?.next?.charOffset ?? -1);
 | 
| +      library.addImport(metadata, uri, conditionalUris, prefix, combinators,
 | 
| +          deferredKeyword != null, importKeyword.charOffset, prefixOffset);
 | 
|      }
 | 
|      checkEmpty(importKeyword.charOffset);
 | 
|    }
 | 
| @@ -155,11 +169,13 @@ class OutlineBuilder extends UnhandledListener {
 | 
|    void handleRecoverExpression(Token token) {
 | 
|      debugEvent("RecoverExpression");
 | 
|      push(NullValue.Expression);
 | 
| +    push(token.charOffset);
 | 
|    }
 | 
|  
 | 
|    @override
 | 
|    void endPart(Token partKeyword, Token semicolon) {
 | 
|      debugEvent("Part");
 | 
| +    popCharOffset();
 | 
|      String uri = pop();
 | 
|      List<MetadataBuilder> metadata = pop();
 | 
|      if (uri != null) {
 | 
| @@ -172,25 +188,68 @@ class OutlineBuilder extends UnhandledListener {
 | 
|    void handleOperatorName(Token operatorKeyword, Token token) {
 | 
|      debugEvent("OperatorName");
 | 
|      push(operatorFromString(token.stringValue));
 | 
| +    push(token.charOffset);
 | 
| +  }
 | 
| +
 | 
| +  @override
 | 
| +  void handleIdentifier(Token token, IdentifierContext context) {
 | 
| +    super.handleIdentifier(token, context);
 | 
| +    push(token.charOffset);
 | 
| +  }
 | 
| +
 | 
| +  @override
 | 
| +  void handleNoName(Token token) {
 | 
| +    super.handleNoName(token);
 | 
| +    push(token.charOffset);
 | 
| +  }
 | 
| +
 | 
| +  @override
 | 
| +  void endLiteralString(int interpolationCount, Token endToken) {
 | 
| +    debugEvent("endLiteralString");
 | 
| +    if (interpolationCount == 0) {
 | 
| +      Token token = pop();
 | 
| +      push(unescapeString(token.lexeme));
 | 
| +      push(token.charOffset);
 | 
| +    } else {
 | 
| +      internalError("String interpolation not implemented.");
 | 
| +    }
 | 
| +  }
 | 
| +
 | 
| +  @override
 | 
| +  void handleStringJuxtaposition(int literalCount) {
 | 
| +    debugEvent("StringJuxtaposition");
 | 
| +    List<String> list =
 | 
| +        new List<String>.filled(literalCount, null, growable: false);
 | 
| +    int charOffset = -1;
 | 
| +    for (int i = literalCount - 1; i >= 0; i--) {
 | 
| +      charOffset = pop();
 | 
| +      list[i] = pop();
 | 
| +    }
 | 
| +    push(list.join(""));
 | 
| +    push(charOffset);
 | 
|    }
 | 
|  
 | 
|    @override
 | 
|    void endIdentifierList(int count) {
 | 
|      debugEvent("endIdentifierList");
 | 
| -    push(popList(count) ?? NullValue.IdentifierList);
 | 
| +    push(popIdentifierList(count) ?? NullValue.IdentifierList);
 | 
|    }
 | 
|  
 | 
|    @override
 | 
|    void handleQualified(Token period) {
 | 
|      debugEvent("handleQualified");
 | 
| +    int charOffset = pop();
 | 
|      String name = pop();
 | 
| +    charOffset = pop(); // We just want the charOffset of receiver.
 | 
|      String receiver = pop();
 | 
|      push("$receiver.$name");
 | 
| +    push(charOffset);
 | 
|    }
 | 
|  
 | 
|    @override
 | 
|    void endLibraryName(Token libraryKeyword, Token semicolon) {
 | 
|      debugEvent("endLibraryName");
 | 
| +    popCharOffset();
 | 
|      String name = pop();
 | 
|      List<MetadataBuilder> metadata = pop();
 | 
|      library.name = name;
 | 
| @@ -214,6 +273,7 @@ class OutlineBuilder extends UnhandledListener {
 | 
|      List<TypeBuilder> interfaces = popList(interfacesCount);
 | 
|      TypeBuilder supertype = pop();
 | 
|      List<TypeVariableBuilder> typeVariables = pop();
 | 
| +    int charOffset = pop();
 | 
|      String name = pop();
 | 
|      if (typeVariables != null && supertype is MixinApplicationBuilder) {
 | 
|        supertype.typeVariables = typeVariables;
 | 
| @@ -222,7 +282,7 @@ class OutlineBuilder extends UnhandledListener {
 | 
|      int modifiers = Modifier.validate(pop());
 | 
|      List<MetadataBuilder> metadata = pop();
 | 
|      library.addClass(metadata, modifiers, name, typeVariables, supertype,
 | 
| -        interfaces, classKeyword.next?.charOffset ?? beginToken.charOffset);
 | 
| +        interfaces, charOffset);
 | 
|      checkEmpty(beginToken.charOffset);
 | 
|    }
 | 
|  
 | 
| @@ -246,6 +306,7 @@ class OutlineBuilder extends UnhandledListener {
 | 
|      List<FormalParameterBuilder> formals = pop();
 | 
|      int formalsOffset = pop();
 | 
|      List<TypeVariableBuilder> typeVariables = pop();
 | 
| +    int charOffset = pop();
 | 
|      String name = pop();
 | 
|      TypeBuilder returnType = pop();
 | 
|      int modifiers =
 | 
| @@ -261,7 +322,7 @@ class OutlineBuilder extends UnhandledListener {
 | 
|          formals,
 | 
|          asyncModifier,
 | 
|          computeProcedureKind(getOrSet),
 | 
| -        beginToken.charOffset,
 | 
| +        charOffset,
 | 
|          formalsOffset,
 | 
|          endToken.charOffset,
 | 
|          nativeMethodName,
 | 
| @@ -298,6 +359,7 @@ class OutlineBuilder extends UnhandledListener {
 | 
|      List<FormalParameterBuilder> formals = pop();
 | 
|      int formalsOffset = pop();
 | 
|      List<TypeVariableBuilder> typeVariables = pop();
 | 
| +    int charOffset = pop();
 | 
|      dynamic nameOrOperator = pop();
 | 
|      if (Operator.subtract == nameOrOperator && formals == null) {
 | 
|        nameOrOperator = Operator.unaryMinus;
 | 
| @@ -324,7 +386,7 @@ class OutlineBuilder extends UnhandledListener {
 | 
|          formals,
 | 
|          asyncModifier,
 | 
|          kind,
 | 
| -        beginToken.charOffset,
 | 
| +        charOffset,
 | 
|          formalsOffset,
 | 
|          endToken.charOffset,
 | 
|          nativeMethodName,
 | 
| @@ -352,6 +414,7 @@ class OutlineBuilder extends UnhandledListener {
 | 
|      List<TypeBuilder> interfaces = popIfNotNull(implementsKeyword);
 | 
|      TypeBuilder mixinApplication = pop();
 | 
|      List<TypeVariableBuilder> typeVariables = pop();
 | 
| +    int charOffset = pop();
 | 
|      String name = pop();
 | 
|      if (typeVariables != null && mixinApplication is MixinApplicationBuilder) {
 | 
|        mixinApplication.typeVariables = typeVariables;
 | 
| @@ -360,7 +423,7 @@ class OutlineBuilder extends UnhandledListener {
 | 
|      int modifiers = Modifier.validate(pop());
 | 
|      List<MetadataBuilder> metadata = pop();
 | 
|      library.addNamedMixinApplication(metadata, name, typeVariables, modifiers,
 | 
| -        mixinApplication, interfaces, beginToken.charOffset);
 | 
| +        mixinApplication, interfaces, charOffset);
 | 
|      checkEmpty(beginToken.charOffset);
 | 
|    }
 | 
|  
 | 
| @@ -379,8 +442,9 @@ class OutlineBuilder extends UnhandledListener {
 | 
|    void handleType(Token beginToken, Token endToken) {
 | 
|      debugEvent("Type");
 | 
|      List<TypeBuilder> arguments = pop();
 | 
| +    int charOffset = pop();
 | 
|      String name = pop();
 | 
| -    push(library.addNamedType(name, arguments, beginToken.charOffset));
 | 
| +    push(library.addNamedType(name, arguments, charOffset));
 | 
|    }
 | 
|  
 | 
|    @override
 | 
| @@ -405,18 +469,13 @@ class OutlineBuilder extends UnhandledListener {
 | 
|    void endFormalParameter(Token covariantKeyword, Token thisKeyword,
 | 
|        Token nameToken, FormalParameterType kind) {
 | 
|      debugEvent("FormalParameter");
 | 
| +    int charOffset = pop();
 | 
|      String name = pop();
 | 
|      TypeBuilder type = pop();
 | 
|      int modifiers = Modifier.validate(pop());
 | 
|      List<MetadataBuilder> metadata = pop();
 | 
| -    // TODO(ahe): Needs begin token.
 | 
|      push(library.addFormalParameter(
 | 
| -        metadata,
 | 
| -        modifiers,
 | 
| -        type,
 | 
| -        name,
 | 
| -        thisKeyword != null,
 | 
| -        thisKeyword?.charOffset ?? nameToken?.charOffset ?? -1));
 | 
| +        metadata, modifiers, type, name, thisKeyword != null, charOffset));
 | 
|    }
 | 
|  
 | 
|    @override
 | 
| @@ -438,10 +497,12 @@ class OutlineBuilder extends UnhandledListener {
 | 
|      pop(); // Function type parameters.
 | 
|      pop(); // Formals offset
 | 
|      pop(); // Type variables.
 | 
| +    int charOffset = pop();
 | 
|      String name = pop();
 | 
|      pop(); // Return type.
 | 
|      push(NullValue.Type);
 | 
|      push(name);
 | 
| +    push(charOffset);
 | 
|    }
 | 
|  
 | 
|    @override
 | 
| @@ -502,11 +563,12 @@ class OutlineBuilder extends UnhandledListener {
 | 
|  
 | 
|    @override
 | 
|    void endEnum(Token enumKeyword, Token endBrace, int count) {
 | 
| -    List<String> constants = popList(count);
 | 
| +    List constantNamesAndOffsets = popList(count * 2);
 | 
| +    int charOffset = pop();
 | 
|      String name = pop();
 | 
|      List<MetadataBuilder> metadata = pop();
 | 
| -    library.addEnum(
 | 
| -        metadata, name, constants, enumKeyword.charOffset, endBrace.charOffset);
 | 
| +    library.addEnum(metadata, name, constantNamesAndOffsets, charOffset,
 | 
| +        endBrace.charOffset);
 | 
|      checkEmpty(enumKeyword.charOffset);
 | 
|    }
 | 
|  
 | 
| @@ -534,15 +596,18 @@ class OutlineBuilder extends UnhandledListener {
 | 
|      List<TypeVariableBuilder> typeVariables;
 | 
|      String name;
 | 
|      TypeBuilder returnType;
 | 
| +    int charOffset;
 | 
|      if (equals == null) {
 | 
|        formals = pop();
 | 
|        pop(); // formals offset
 | 
|        typeVariables = pop();
 | 
| +      charOffset = pop();
 | 
|        name = pop();
 | 
|        returnType = pop();
 | 
|      } else {
 | 
|        var type = pop();
 | 
|        typeVariables = pop();
 | 
| +      charOffset = pop();
 | 
|        name = pop();
 | 
|        if (type is FunctionTypeBuilder) {
 | 
|          // TODO(ahe): We need to start a nested declaration when parsing the
 | 
| @@ -559,19 +624,19 @@ class OutlineBuilder extends UnhandledListener {
 | 
|        }
 | 
|      }
 | 
|      List<MetadataBuilder> metadata = pop();
 | 
| -    library.addFunctionTypeAlias(metadata, returnType, name, typeVariables,
 | 
| -        formals, typedefKeyword.charOffset);
 | 
| +    library.addFunctionTypeAlias(
 | 
| +        metadata, returnType, name, typeVariables, formals, charOffset);
 | 
|      checkEmpty(typedefKeyword.charOffset);
 | 
|    }
 | 
|  
 | 
|    @override
 | 
|    void endTopLevelFields(int count, Token beginToken, Token endToken) {
 | 
|      debugEvent("endTopLevelFields");
 | 
| -    List<String> names = popList(count);
 | 
| +    List namesAndOffsets = popList(count * 2);
 | 
|      TypeBuilder type = pop();
 | 
|      int modifiers = Modifier.validate(pop());
 | 
|      List<MetadataBuilder> metadata = pop();
 | 
| -    library.addFields(metadata, modifiers, type, names);
 | 
| +    library.addFields(metadata, modifiers, type, namesAndOffsets);
 | 
|      checkEmpty(beginToken.charOffset);
 | 
|    }
 | 
|  
 | 
| @@ -579,27 +644,29 @@ class OutlineBuilder extends UnhandledListener {
 | 
|    void endFields(
 | 
|        int count, Token covariantToken, Token beginToken, Token endToken) {
 | 
|      debugEvent("Fields");
 | 
| -    List<String> names = popList(count);
 | 
| +    List namesAndOffsets = popList(count * 2);
 | 
|      TypeBuilder type = pop();
 | 
|      int modifiers = Modifier.validate(pop());
 | 
|      List<MetadataBuilder> metadata = pop();
 | 
| -    library.addFields(metadata, modifiers, type, names);
 | 
| +    library.addFields(metadata, modifiers, type, namesAndOffsets);
 | 
|    }
 | 
|  
 | 
|    @override
 | 
|    void endTypeVariable(Token token, Token extendsOrSuper) {
 | 
|      debugEvent("endTypeVariable");
 | 
|      TypeBuilder bound = pop();
 | 
| +    int charOffset = pop();
 | 
|      String name = pop();
 | 
|      // TODO(paulberry): type variable metadata should not be ignored.  See
 | 
|      // dartbug.com/28981.
 | 
|      /* List<MetadataBuilder> metadata = */ pop();
 | 
| -    push(library.addTypeVariable(name, bound, token.charOffset));
 | 
| +    push(library.addTypeVariable(name, bound, charOffset));
 | 
|    }
 | 
|  
 | 
|    @override
 | 
|    void endPartOf(Token partKeyword, Token semicolon, bool hasName) {
 | 
|      debugEvent("endPartOf");
 | 
| +    popCharOffset();
 | 
|      String containingLibrary = pop();
 | 
|      List<MetadataBuilder> metadata = pop();
 | 
|      if (hasName) {
 | 
| @@ -613,11 +680,13 @@ class OutlineBuilder extends UnhandledListener {
 | 
|    void endConstructorReference(
 | 
|        Token start, Token periodBeforeName, Token endToken) {
 | 
|      debugEvent("ConstructorReference");
 | 
| +    popIfNotNull(periodBeforeName); // charOffset.
 | 
|      String suffix = popIfNotNull(periodBeforeName);
 | 
|      List<TypeBuilder> typeArguments = pop();
 | 
| +    int charOffset = pop();
 | 
|      String name = pop();
 | 
|      push(library.addConstructorReference(
 | 
| -        name, typeArguments, suffix, start.charOffset));
 | 
| +        name, typeArguments, suffix, charOffset));
 | 
|    }
 | 
|  
 | 
|    @override
 | 
| @@ -647,7 +716,7 @@ class OutlineBuilder extends UnhandledListener {
 | 
|          formals,
 | 
|          asyncModifier,
 | 
|          redirectionTarget,
 | 
| -        beginToken.charOffset,
 | 
| +        factoryKeyword.next.charOffset,
 | 
|          formalsOffset,
 | 
|          endToken.charOffset,
 | 
|          nativeMethodName);
 | 
| 
 |