Resolve namespace combinators.

R=brianwilkerson@google.com, paulberry@google.com

Bug: https://github.com/dart-lang/sdk/issues/33636
Change-Id: I4f16eec2dcb5805663c0118d221f8ad8710cf3f8
Reviewed-on: https://dart-review.googlesource.com/71220
Reviewed-by: Paul Berry <paulberry@google.com>
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/frontend_resolution.dart b/pkg/analyzer/lib/src/dart/analysis/frontend_resolution.dart
index 578c149..2d056ef 100644
--- a/pkg/analyzer/lib/src/dart/analysis/frontend_resolution.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/frontend_resolution.dart
@@ -443,12 +443,16 @@
 
   @override
   void store(int offset, bool isSynthetic,
-      {int importIndex, Node reference, DartType type}) {
+      {int importIndex,
+      bool isNamespaceCombinatorReference = false,
+      Node reference,
+      DartType type}) {
 //    if (fileUri.toString().endsWith('test.dart')) {
 //      print('[store][offset: $offset][reference: $reference][type: $type]');
 //    }
     var encodedLocation = 2 * offset + (isSynthetic ? 1 : 0);
     resolution.kernelData[encodedLocation] = new ResolutionData(
+        isNamespaceCombinatorReference: isNamespaceCombinatorReference,
         isOutline: true,
         prefixInfo: importIndex,
         reference: reference,
diff --git a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
index 487f11f..d5a934b 100644
--- a/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/library_analyzer.dart
@@ -741,6 +741,9 @@
       if (directive.metadata.isNotEmpty) {
         applier.applyToAnnotations(directive);
       }
+      if (directive is NamespaceDirective) {
+        directive.combinators.accept(applier);
+      }
     }
     for (var declaration in unit.declarations) {
       if (declaration is ClassDeclaration) {
@@ -1133,8 +1136,9 @@
 
   @override
   Element translateReference(kernel.Node referencedNode,
-      {bool isWriteReference = false,
+      {bool isNamespaceCombinatorReference = false,
       bool isTypeReference = false,
+      bool isWriteReference = false,
       kernel.DartType inferredType,
       kernel.DartType receiverType}) {
     if (referencedNode == null) {
@@ -1169,6 +1173,9 @@
       throw new UnimplementedError(
           'TODO(paulberry): ${referencedNode.runtimeType}');
     }
+    if (isNamespaceCombinatorReference) {
+      return element;
+    }
     if (element is PropertyInducingElement) {
       PropertyInducingElement property = element;
       element = isWriteReference ? property.setter : property.getter;
diff --git a/pkg/analyzer/lib/src/fasta/resolution_applier.dart b/pkg/analyzer/lib/src/fasta/resolution_applier.dart
index 6a416b6..3c913ce 100644
--- a/pkg/analyzer/lib/src/fasta/resolution_applier.dart
+++ b/pkg/analyzer/lib/src/fasta/resolution_applier.dart
@@ -919,8 +919,9 @@
       return _translatePrefixInfo(data.prefixInfo);
     }
     return _typeContext.translateReference(data.reference,
-        isWriteReference: data.isWriteReference,
+        isNamespaceCombinatorReference: data.isNamespaceCombinatorReference,
         isTypeReference: data.isTypeReference,
+        isWriteReference: data.isWriteReference,
         inferredType: data.inferredType,
         receiverType: data.receiverType);
   }
@@ -977,8 +978,9 @@
 
   /// Return the analyzer [Element] for the given kernel node.
   Element translateReference(kernel.Node referencedNode,
-      {bool isWriteReference = false,
+      {bool isNamespaceCombinatorReference = false,
       bool isTypeReference = false,
+      bool isWriteReference = false,
       kernel.DartType inferredType,
       kernel.DartType receiverType});
 
diff --git a/pkg/analyzer/lib/src/fasta/resolution_storer.dart b/pkg/analyzer/lib/src/fasta/resolution_storer.dart
index 4301ba0..04e1c84 100644
--- a/pkg/analyzer/lib/src/fasta/resolution_storer.dart
+++ b/pkg/analyzer/lib/src/fasta/resolution_storer.dart
@@ -18,6 +18,7 @@
   final DartType invokeType;
   final bool isExplicitCall;
   final bool isImplicitCall;
+  final bool isNamespaceCombinatorReference;
   final bool isOutline;
   final bool isPrefixReference;
   final bool isTypeReference;
@@ -36,6 +37,7 @@
       this.invokeType,
       this.isExplicitCall = false,
       this.isImplicitCall = false,
+      this.isNamespaceCombinatorReference = false,
       this.isOutline = false,
       this.isPrefixReference = false,
       this.isTypeReference = false,
diff --git a/pkg/analyzer/test/generated/hint_code_kernel_test.dart b/pkg/analyzer/test/generated/hint_code_kernel_test.dart
index 3e9f85c..ebc8fb6 100644
--- a/pkg/analyzer/test/generated/hint_code_kernel_test.dart
+++ b/pkg/analyzer/test/generated/hint_code_kernel_test.dart
@@ -83,18 +83,6 @@
     return super.test_deprecatedFunction_mixin2();
   }
 
-  @failingTest
-  @override
-  test_duplicateShownHiddenName_hidden() {
-    return super.test_duplicateShownHiddenName_hidden();
-  }
-
-  @failingTest
-  @override
-  test_duplicateShownHiddenName_shown() {
-    return super.test_duplicateShownHiddenName_shown();
-  }
-
   @override
   @failingTest
   test_invalidRequiredParam_on_named_parameter_with_default() async {
@@ -184,28 +172,4 @@
   test_unusedImport_inComment_libraryDirective() async {
     return super.test_unusedImport_inComment_libraryDirective();
   }
-
-  @failingTest
-  @override
-  test_unusedShownName() async {
-    return super.test_unusedShownName();
-  }
-
-  @failingTest
-  @override
-  test_unusedShownName_as() async {
-    return super.test_unusedShownName_as();
-  }
-
-  @failingTest
-  @override
-  test_unusedShownName_duplicates() async {
-    return super.test_unusedShownName_duplicates();
-  }
-
-  @failingTest
-  @override
-  test_unusedShownName_topLevelVariable() async {
-    return super.test_unusedShownName_topLevelVariable();
-  }
 }
diff --git a/pkg/analyzer/test/generated/non_error_resolver_kernel_test.dart b/pkg/analyzer/test/generated/non_error_resolver_kernel_test.dart
index 844dfeb..0c3c7dc 100644
--- a/pkg/analyzer/test/generated/non_error_resolver_kernel_test.dart
+++ b/pkg/analyzer/test/generated/non_error_resolver_kernel_test.dart
@@ -40,13 +40,6 @@
 
   @override
   @failingTest
-  @AnalyzerProblem('https://github.com/dart-lang/sdk/issues/33636')
-  test_ambiguousImport_showCombinator() async {
-    return super.test_ambiguousImport_showCombinator();
-  }
-
-  @override
-  @failingTest
   @FastaProblem('https://github.com/dart-lang/sdk/issues/31604')
   test_commentReference_beforeConstructor() async {
     return super.test_commentReference_beforeConstructor();
diff --git a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
index 454fd79..11ab373 100644
--- a/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/driver_resolution_test.dart
@@ -2533,7 +2533,6 @@
 main() {
   a.loadLibrary();
 }
-
 ''');
     await resolveTestFile();
     var import = findElement.import('package:test/a.dart');
@@ -2561,7 +2560,6 @@
 main() {
   a.loadLibrary(b, c);
 }
-
 ''');
     await resolveTestFile();
     var import = findElement.import('package:test/a.dart');
@@ -2595,7 +2593,6 @@
 main() {
   a.loadLibrary;
 }
-
 ''');
     await resolveTestFile();
     var import = findElement.import('package:test/a.dart');
@@ -2621,7 +2618,6 @@
   a.v;
   a.v = 1;
 }
-
 ''');
     await resolveTestFile();
     var import = findElement.import('package:test/a.dart');
@@ -2654,6 +2650,153 @@
     }
   }
 
+  test_directive_export() async {
+    var a = _p('/test/lib/a.dart');
+    provider.newFile(a, r'''
+class MyClass {}
+int myVar;
+int get myGetter => 0;
+int set mySetter(_) {}
+''');
+    addTestFile(r'''
+export 'a.dart' show MyClass, myVar, myGetter, mySetter, Unresolved;
+''');
+    await resolveTestFile();
+    var export = findElement.export('package:test/a.dart');
+    var namespace = export.exportedLibrary.exportNamespace;
+
+    {
+      var ref = findNode.simple('MyClass');
+      assertElement(ref, namespace.get('MyClass'));
+      assertType(ref, null);
+    }
+
+    {
+      var ref = findNode.simple('myVar');
+      PropertyAccessorElement getter = namespace.get('myVar');
+      assertElement(ref, getter.variable);
+      assertType(ref, null);
+    }
+
+    {
+      var ref = findNode.simple('myGetter');
+      PropertyAccessorElement getter = namespace.get('myGetter');
+      assertElement(ref, getter.variable);
+      assertType(ref, null);
+    }
+
+    {
+      var ref = findNode.simple('mySetter');
+      PropertyAccessorElement getter = namespace.get('mySetter=');
+      assertElement(ref, getter.variable);
+      assertType(ref, null);
+    }
+
+    {
+      var ref = findNode.simple('Unresolved');
+      assertElementNull(ref);
+      assertType(ref, null);
+    }
+  }
+
+  test_directive_import_hide() async {
+    var a = _p('/test/lib/a.dart');
+    provider.newFile(a, r'''
+class MyClass {}
+int myVar;
+int get myGetter => 0;
+int set mySetter(_) {}
+''');
+    addTestFile(r'''
+import 'a.dart' hide MyClass, myVar, myGetter, mySetter, Unresolved;
+''');
+    await resolveTestFile();
+    var import = findElement.import('package:test/a.dart');
+    var namespace = import.importedLibrary.exportNamespace;
+
+    {
+      var ref = findNode.simple('MyClass');
+      assertElement(ref, namespace.get('MyClass'));
+      assertType(ref, null);
+    }
+
+    {
+      var ref = findNode.simple('myVar');
+      PropertyAccessorElement getter = namespace.get('myVar');
+      assertElement(ref, getter.variable);
+      assertType(ref, null);
+    }
+
+    {
+      var ref = findNode.simple('myGetter');
+      PropertyAccessorElement getter = namespace.get('myGetter');
+      assertElement(ref, getter.variable);
+      assertType(ref, null);
+    }
+
+    {
+      var ref = findNode.simple('mySetter');
+      PropertyAccessorElement getter = namespace.get('mySetter=');
+      assertElement(ref, getter.variable);
+      assertType(ref, null);
+    }
+
+    {
+      var ref = findNode.simple('Unresolved');
+      assertElementNull(ref);
+      assertType(ref, null);
+    }
+  }
+
+  test_directive_import_show() async {
+    var a = _p('/test/lib/a.dart');
+    provider.newFile(a, r'''
+class MyClass {}
+int myVar;
+int get myGetter => 0;
+int set mySetter(_) {}
+''');
+    addTestFile(r'''
+import 'a.dart' show MyClass, myVar, myGetter, mySetter, Unresolved;
+''');
+    await resolveTestFile();
+    var import = findElement.import('package:test/a.dart');
+    var namespace = import.importedLibrary.exportNamespace;
+
+    {
+      var ref = findNode.simple('MyClass');
+      assertElement(ref, namespace.get('MyClass'));
+      assertType(ref, null);
+    }
+
+    {
+      var ref = findNode.simple('myVar');
+      PropertyAccessorElement getter = namespace.get('myVar');
+      assertElement(ref, getter.variable);
+      assertType(ref, null);
+    }
+
+    {
+      var ref = findNode.simple('myGetter');
+      PropertyAccessorElement getter = namespace.get('myGetter');
+      assertElement(ref, getter.variable);
+      assertType(ref, null);
+    }
+
+    {
+      var ref = findNode.simple('mySetter');
+      PropertyAccessorElement getter = namespace.get('mySetter=');
+      assertElement(ref, getter.variable);
+      assertType(ref, null);
+    }
+
+    {
+      var ref = findNode.simple('Unresolved');
+      assertElementNull(ref);
+      assertType(ref, null);
+    }
+  }
+
   test_enum_toString() async {
     addTestFile(r'''
 enum MyEnum { A, B, C }
@@ -10353,6 +10496,23 @@
     fail('Not found class: $name');
   }
 
+  ExportElement export(String targetUri) {
+    ExportElement exportElement;
+    for (var export in unitElement.library.exports) {
+      var exportedUri = export.exportedLibrary.source.uri.toString();
+      if (exportedUri == targetUri) {
+        if (exportElement != null) {
+          throw new StateError('Not unique $targetUri export.');
+        }
+        exportElement = export;
+      }
+    }
+    if (exportElement != null) {
+      return exportElement;
+    }
+    fail('Not found export: $targetUri');
+  }
+
   FieldElement field(String name) {
     for (var type in unitElement.types) {
       for (var field in type.fields) {
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index 7a7e093..53e073e 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -1994,11 +1994,6 @@
 
   @failingTest
   @override
-  test_searchReferences_TopLevelVariableElement() =>
-      super.test_searchReferences_TopLevelVariableElement();
-
-  @failingTest
-  @override
   test_subtypes_partWithoutLibrary() =>
       super.test_subtypes_partWithoutLibrary();
 }
diff --git a/pkg/front_end/lib/src/fasta/combinator.dart b/pkg/front_end/lib/src/fasta/combinator.dart
index 9f97607..5dfcf91 100644
--- a/pkg/front_end/lib/src/fasta/combinator.dart
+++ b/pkg/front_end/lib/src/fasta/combinator.dart
@@ -7,15 +7,30 @@
 class Combinator {
   final bool isShow;
 
+  final List<CombinatorIdentifier> identifiers;
+
   final Set<String> names;
 
-  Combinator(this.isShow, this.names, int charOffset, Uri fileUri);
+  Combinator(
+      this.isShow, this.identifiers, this.names, int charOffset, Uri fileUri);
 
-  Combinator.show(Iterable<String> names, int charOffset, Uri fileUri)
-      : this(true, new Set<String>.from(names), charOffset, fileUri);
+  Combinator.hide(List<CombinatorIdentifier> identifiers,
+      Iterable<String> names, int charOffset, Uri fileUri)
+      : this(false, identifiers, new Set<String>.from(names), charOffset,
+            fileUri);
 
-  Combinator.hide(Iterable<String> names, int charOffset, Uri fileUri)
-      : this(false, new Set<String>.from(names), charOffset, fileUri);
+  Combinator.show(List<CombinatorIdentifier> identifiers,
+      Iterable<String> names, int charOffset, Uri fileUri)
+      : this(true, identifiers, new Set<String>.from(names), charOffset,
+            fileUri);
 
   bool get isHide => !isShow;
 }
+
+class CombinatorIdentifier {
+  final int offset;
+  final String name;
+  final bool isSynthetic;
+
+  CombinatorIdentifier(this.offset, this.name, this.isSynthetic);
+}
diff --git a/pkg/front_end/lib/src/fasta/incremental_compiler.dart b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
index 476c2da..399112b 100644
--- a/pkg/front_end/lib/src/fasta/incremental_compiler.dart
+++ b/pkg/front_end/lib/src/fasta/incremental_compiler.dart
@@ -469,10 +469,10 @@
             combinators ??= <Combinator>[];
 
             combinators.add(combinator.isShow
-                ? new Combinator.show(
-                    combinator.names, combinator.fileOffset, library.fileUri)
-                : new Combinator.hide(
-                    combinator.names, combinator.fileOffset, library.fileUri));
+                ? new Combinator.show(null, combinator.names,
+                    combinator.fileOffset, library.fileUri)
+                : new Combinator.hide(null, combinator.names,
+                    combinator.fileOffset, library.fileUri));
           }
 
           debugLibrary.addImport(
diff --git a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
index 11ed95df..5d79c08 100644
--- a/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/kernel/kernel_library_builder.dart
@@ -65,8 +65,6 @@
 
 import '../problems.dart' show unexpected, unhandled;
 
-import '../source/outline_listener.dart' show OutlineListener;
-
 import '../source/source_class_builder.dart' show SourceClassBuilder;
 
 import '../source/source_library_builder.dart'
@@ -150,13 +148,10 @@
   /// the error message is the corresponding value in the map.
   Map<String, String> unserializableExports;
 
-  final OutlineListener outlineListener;
-
   KernelLibraryBuilder(Uri uri, Uri fileUri, Loader loader, this.actualOrigin,
       [Scope scope, Library target])
       : library = target ??
             (actualOrigin?.library ?? new Library(uri, fileUri: fileUri)),
-        outlineListener = loader.createOutlineListener(fileUri),
         super(loader, fileUri, scope);
 
   @override
diff --git a/pkg/front_end/lib/src/fasta/parser/identifier_context.dart b/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
index 460fec9..83d9acd 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context.dart
@@ -240,6 +240,9 @@
   /// expressions are required.
   final bool allowedInConstantExpression;
 
+  /// Indicated whether the `isSynthetic` flag is required for the identifier.
+  final bool requiresSyntheticFlag;
+
   final Template<_MessageWithArgument<Token>> recoveryTemplate;
 
   const IdentifierContext(this._name,
@@ -249,6 +252,7 @@
       this.isContinuation: false,
       this.isScopeReference: false,
       this.isBuiltInIdentifierAllowed: true,
+      this.requiresSyntheticFlag: false,
       bool allowedInConstantExpression,
       this.recoveryTemplate: templateExpectedIdentifier})
       : this.allowedInConstantExpression =
diff --git a/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart b/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
index 9814c3b..078f2d6 100644
--- a/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
+++ b/pkg/front_end/lib/src/fasta/parser/identifier_context_impl.dart
@@ -81,7 +81,8 @@
 
 /// See [IdentifierContext.combinator].
 class CombinatorIdentifierContext extends IdentifierContext {
-  const CombinatorIdentifierContext() : super('combinator');
+  const CombinatorIdentifierContext()
+      : super('combinator', requiresSyntheticFlag: true);
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
@@ -154,10 +155,12 @@
 
 /// See [IdentifierContext.dottedName].
 class DottedNameIdentifierContext extends IdentifierContext {
-  const DottedNameIdentifierContext() : super('dottedName');
+  const DottedNameIdentifierContext()
+      : super('dottedName', requiresSyntheticFlag: true);
 
   const DottedNameIdentifierContext.continuation()
-      : super('dottedNameContinuation', isContinuation: true);
+      : super('dottedNameContinuation',
+            isContinuation: true, requiresSyntheticFlag: true);
 
   @override
   Token ensureIdentifier(Token token, Parser parser) {
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 d487929..6fc54ed 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_builder.dart
@@ -14,7 +14,7 @@
 
 import '../builder/metadata_builder.dart' show ExpressionMetadataBuilder;
 
-import '../combinator.dart' show Combinator;
+import '../combinator.dart' show Combinator, CombinatorIdentifier;
 
 import '../fasta_codes.dart'
     show
@@ -113,12 +113,14 @@
 
   int popCharOffset() => pop();
 
-  List<String> popIdentifierList(int count) {
+  List<CombinatorIdentifier> popIdentifierList(int count) {
     if (count == 0) return null;
-    List<String> list = new List<String>.filled(count, null, growable: true);
+    var list = new List<CombinatorIdentifier>.filled(count, null);
     for (int i = count - 1; i >= 0; i--) {
-      popCharOffset();
-      list[i] = pop();
+      bool isSynthetic = pop();
+      int offset = popCharOffset();
+      String name = pop();
+      list[i] = new CombinatorIdentifier(offset, name, isSynthetic);
     }
     return list;
   }
@@ -177,15 +179,21 @@
   @override
   void endHide(Token hideKeyword) {
     debugEvent("Hide");
-    List<String> names = pop();
-    push(new Combinator.hide(names, hideKeyword.charOffset, library.fileUri));
+    List<CombinatorIdentifier> identifiers = pop();
+    List<String> names =
+        identifiers.map((identifier) => identifier.name).toList();
+    push(new Combinator.hide(
+        identifiers, names, hideKeyword.charOffset, library.fileUri));
   }
 
   @override
   void endShow(Token showKeyword) {
     debugEvent("Show");
-    List<String> names = pop();
-    push(new Combinator.show(names, showKeyword.charOffset, library.fileUri));
+    List<CombinatorIdentifier> identifiers = pop();
+    List<String> names =
+        identifiers.map((identifier) => identifier.name).toList();
+    push(new Combinator.show(
+        identifiers, names, showKeyword.charOffset, library.fileUri));
   }
 
   @override
@@ -270,7 +278,9 @@
   @override
   void handleDottedName(int count, Token firstIdentifier) {
     debugEvent("DottedName");
-    push(popIdentifierList(count).join('.'));
+    push(popIdentifierList(count)
+        .map((identifier) => identifier.name)
+        .join('.'));
   }
 
   @override
@@ -319,6 +329,9 @@
       super.handleIdentifier(token, context);
       push(token.charOffset);
     }
+    if (context.requiresSyntheticFlag) {
+      push(token.isSynthetic);
+    }
     if (inConstructor && context == IdentifierContext.methodDeclaration) {
       inConstructorName = true;
     }
diff --git a/pkg/front_end/lib/src/fasta/source/outline_listener.dart b/pkg/front_end/lib/src/fasta/source/outline_listener.dart
index 4728332..0f77d6c 100644
--- a/pkg/front_end/lib/src/fasta/source/outline_listener.dart
+++ b/pkg/front_end/lib/src/fasta/source/outline_listener.dart
@@ -22,5 +22,8 @@
   /// `List<int>` will have a reference to `List` and type `List<int>`, i.e.
   /// with type arguments applied.
   void store(int offset, bool isSynthetic,
-      {int importIndex, Node reference, DartType type}) {}
+      {int importIndex,
+      bool isNamespaceCombinatorReference,
+      Node reference,
+      DartType type}) {}
 }
diff --git a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
index e6a127e..75ee308 100644
--- a/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_library_builder.dart
@@ -65,6 +65,8 @@
 
 import '../problems.dart' show unhandled;
 
+import '../source/outline_listener.dart' show OutlineListener;
+
 import 'source_loader.dart' show SourceLoader;
 
 abstract class SourceLibraryBuilder<T extends TypeBuilder, R>
@@ -113,6 +115,8 @@
 
   bool canAddImplementationBuilders = false;
 
+  final OutlineListener outlineListener;
+
   SourceLibraryBuilder(SourceLoader loader, Uri fileUri, Scope scope)
       : this.fromScopes(loader, fileUri, new DeclarationBuilder<T>.library(),
             scope ?? new Scope.top());
@@ -121,6 +125,7 @@
       this.loader, this.fileUri, this.libraryDeclaration, this.importScope)
       : disableTypeInference = loader.target.disableTypeInference,
         currentDeclaration = libraryDeclaration,
+        outlineListener = loader.createOutlineListener(fileUri),
         super(
             fileUri, libraryDeclaration.toScope(importScope), new Scope.top());
 
diff --git a/pkg/front_end/lib/src/fasta/source/source_loader.dart b/pkg/front_end/lib/src/fasta/source/source_loader.dart
index 16e03ba..9c65335 100644
--- a/pkg/front_end/lib/src/fasta/source/source_loader.dart
+++ b/pkg/front_end/lib/src/fasta/source/source_loader.dart
@@ -45,6 +45,8 @@
         NamedTypeBuilder,
         TypeBuilder;
 
+import '../combinator.dart';
+
 import '../deprecated_problems.dart' show deprecated_inputError;
 
 import '../export.dart' show Export;
@@ -102,6 +104,8 @@
 
 import 'outline_builder.dart' show OutlineBuilder;
 
+import 'outline_listener.dart' show OutlineListener;
+
 import 'source_class_builder.dart' show SourceClassBuilder;
 
 import 'source_library_builder.dart' show SourceLibraryBuilder;
@@ -344,6 +348,21 @@
       // and can lead to memory leaks.
       exportee.exporters.clear();
     }
+    for (var library in builders.values) {
+      if (library is SourceLibraryBuilder) {
+        OutlineListener outlineListener = library.outlineListener;
+        if (outlineListener != null) {
+          for (var import in library.imports) {
+            storeCombinatorIdentifiersResolution(
+                outlineListener, import.imported, import.combinators);
+          }
+          for (var export in library.exports) {
+            storeCombinatorIdentifiersResolution(
+                outlineListener, export.exported, export.combinators);
+          }
+        }
+      }
+    }
     ticker.logMs("Computed library scopes");
     // debugPrintExports();
   }
@@ -953,4 +972,19 @@
     hierarchy = null;
     typeInferenceEngine = null;
   }
+
+  void storeCombinatorIdentifiersResolution(OutlineListener outlineListener,
+      LibraryBuilder consumed, List<Combinator> combinators) {
+    if (combinators != null) {
+      for (var combinator in combinators) {
+        for (var identifier in combinator.identifiers) {
+          var declaration = consumed.exportScope.local[identifier.name];
+          declaration ??= consumed.exportScope.setters[identifier.name];
+          outlineListener.store(identifier.offset, identifier.isSynthetic,
+              isNamespaceCombinatorReference: true,
+              reference: declaration?.target);
+        }
+      }
+    }
+  }
 }