Version 2.14.0-66.0.dev

Merge commit '9d015feeaf5617205dc431568c024fed7eec23d9' into 'dev'
diff --git a/.dart_tool/package_config.json b/.dart_tool/package_config.json
index ca2f072..7109004 100644
--- a/.dart_tool/package_config.json
+++ b/.dart_tool/package_config.json
@@ -11,7 +11,7 @@
     "constraint, update this by running tools/generate_package_config.dart."
   ],
   "configVersion": 2,
-  "generated": "2021-04-29T10:51:01.320402",
+  "generated": "2021-04-29T17:48:25.665083",
   "generator": "tools/generate_package_config.dart",
   "packages": [
     {
diff --git a/DEPS b/DEPS
index bbac264..78974f4 100644
--- a/DEPS
+++ b/DEPS
@@ -73,7 +73,7 @@
 
   # Revisions of /third_party/* dependencies.
   "args_rev": "d8fea36c10ef96797be02e3d132d572445cd86f4",
-  "async_rev": "06774f59a7cf9780e08148298d438c1043e2b063",
+  "async_rev": "cde00b89bd3c19e877b21de2c02282d4d311d0a5",
   "bazel_worker_rev": "0885637b037979afbf5bcd05fd748b309fd669c0",
   "benchmark_harness_rev": "c546dbd9f639f75cd2f75de8df2eb9f8ea15e8e7",
   "boolean_selector_rev": "665e6921ab246569420376f827bff4585dff0b14",
diff --git a/pkg/analysis_server/bin/server.dart b/pkg/analysis_server/bin/server.dart
index 7810101..a873eb1 100644
--- a/pkg/analysis_server/bin/server.dart
+++ b/pkg/analysis_server/bin/server.dart
@@ -2,6 +2,8 @@
 // for details. All rights reserved. Use of this source code is governed by a
 // BSD-style license that can be found in the LICENSE file.
 
+// @dart = 2.9
+
 import 'package:analysis_server/starter.dart';
 
 /// Create and run an analysis server.
diff --git a/pkg/analysis_server/lib/src/lsp/constants.dart b/pkg/analysis_server/lib/src/lsp/constants.dart
index 4afc13e..7f10b84 100644
--- a/pkg/analysis_server/lib/src/lsp/constants.dart
+++ b/pkg/analysis_server/lib/src/lsp/constants.dart
@@ -104,9 +104,13 @@
   /// - parameter
   static const label = SemanticTokenModifiers('label');
 
+  /// A modifier applied to constructors to allow colouring them differently
+  /// to class names that are not constructors.
+  static const constructor = SemanticTokenModifiers('constructor');
+
   /// All custom semantic token modifiers, used to populate the LSP Legend which must
   /// include all used modifiers.
-  static const values = [control, label];
+  static const values = [control, label, constructor];
 }
 
 abstract class CustomSemanticTokenTypes {
diff --git a/pkg/analysis_server/lib/src/lsp/semantic_tokens/mapping.dart b/pkg/analysis_server/lib/src/lsp/semantic_tokens/mapping.dart
index 66e4b26..c83e229 100644
--- a/pkg/analysis_server/lib/src/lsp/semantic_tokens/mapping.dart
+++ b/pkg/analysis_server/lib/src/lsp/semantic_tokens/mapping.dart
@@ -15,6 +15,7 @@
   HighlightRegionType.COMMENT_DOCUMENTATION: {
     SemanticTokenModifiers.documentation
   },
+  HighlightRegionType.CONSTRUCTOR: {CustomSemanticTokenModifiers.constructor},
   HighlightRegionType.DYNAMIC_LOCAL_VARIABLE_DECLARATION: {
     SemanticTokenModifiers.declaration
   },
diff --git a/pkg/analysis_server/test/lsp/semantic_tokens_test.dart b/pkg/analysis_server/test/lsp/semantic_tokens_test.dart
index 6fcc641..20d0bfc 100644
--- a/pkg/analysis_server/test/lsp/semantic_tokens_test.dart
+++ b/pkg/analysis_server/test/lsp/semantic_tokens_test.dart
@@ -82,6 +82,46 @@
     expect(decoded, equals(expected));
   }
 
+  Future<void> test_class_constructors() async {
+    final content = '''
+    class MyClass {
+      MyClass();
+      MyClass.named();
+    }
+
+    final a = MyClass();
+    final b = MyClass.named();
+    ''';
+
+    final expected = [
+      _Token('class', SemanticTokenTypes.keyword),
+      _Token('MyClass', SemanticTokenTypes.class_),
+      _Token('MyClass', SemanticTokenTypes.class_),
+      _Token('MyClass', SemanticTokenTypes.class_),
+      _Token('named', SemanticTokenTypes.class_,
+          [CustomSemanticTokenModifiers.constructor]),
+      _Token('final', SemanticTokenTypes.keyword),
+      _Token('a', SemanticTokenTypes.variable,
+          [SemanticTokenModifiers.declaration]),
+      _Token('MyClass', SemanticTokenTypes.class_,
+          [CustomSemanticTokenModifiers.constructor]),
+      _Token('final', SemanticTokenTypes.keyword),
+      _Token('b', SemanticTokenTypes.variable,
+          [SemanticTokenModifiers.declaration]),
+      _Token('MyClass', SemanticTokenTypes.class_,
+          [CustomSemanticTokenModifiers.constructor]),
+      _Token('named', SemanticTokenTypes.class_,
+          [CustomSemanticTokenModifiers.constructor])
+    ];
+
+    await initialize();
+    await openFile(mainFileUri, withoutMarkers(content));
+
+    final tokens = await getSemanticTokens(mainFileUri);
+    final decoded = decodeSemanticTokens(content, tokens);
+    expect(decoded, equals(expected));
+  }
+
   Future<void> test_class_fields() async {
     final content = '''
     class MyClass {
@@ -119,7 +159,8 @@
       _Token('final', SemanticTokenTypes.keyword),
       _Token('a', SemanticTokenTypes.variable,
           [SemanticTokenModifiers.declaration]),
-      _Token('MyClass', SemanticTokenTypes.class_),
+      _Token('MyClass', SemanticTokenTypes.class_,
+          [CustomSemanticTokenModifiers.constructor]),
       _Token('print', SemanticTokenTypes.function),
       _Token('a', SemanticTokenTypes.variable),
       _Token('myField', SemanticTokenTypes.property),
@@ -197,7 +238,8 @@
       _Token('final', SemanticTokenTypes.keyword),
       _Token('a', SemanticTokenTypes.variable,
           [SemanticTokenModifiers.declaration]),
-      _Token('MyClass', SemanticTokenTypes.class_),
+      _Token('MyClass', SemanticTokenTypes.class_,
+          [CustomSemanticTokenModifiers.constructor]),
       _Token('print', SemanticTokenTypes.function),
       _Token('a', SemanticTokenTypes.variable),
       _Token('myGetter', SemanticTokenTypes.property),
@@ -255,7 +297,8 @@
       _Token('final', SemanticTokenTypes.keyword),
       _Token('a', SemanticTokenTypes.variable,
           [SemanticTokenModifiers.declaration]),
-      _Token('MyClass', SemanticTokenTypes.class_),
+      _Token('MyClass', SemanticTokenTypes.class_,
+          [CustomSemanticTokenModifiers.constructor]),
       _Token('a', SemanticTokenTypes.variable),
       _Token('myMethod', SemanticTokenTypes.method),
       _Token('MyClass', SemanticTokenTypes.class_),
@@ -443,7 +486,8 @@
       _Token('a', SemanticTokenTypes.variable,
           [SemanticTokenModifiers.declaration]),
       _Token('new', SemanticTokenTypes.keyword),
-      _Token('Object', SemanticTokenTypes.class_),
+      _Token('Object', SemanticTokenTypes.class_,
+          [CustomSemanticTokenModifiers.constructor]),
       _Token('await', SemanticTokenTypes.keyword,
           [CustomSemanticTokenModifiers.control]),
       _Token('null', SemanticTokenTypes.keyword),
diff --git a/pkg/analyzer/lib/src/dart/micro/library_graph.dart b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
index 2c10c45..0d6ea0b 100644
--- a/pkg/analyzer/lib/src/dart/micro/library_graph.dart
+++ b/pkg/analyzer/lib/src/dart/micro/library_graph.dart
@@ -518,6 +518,10 @@
   /// to batch file reads in systems where file fetches are expensive.
   final void Function(List<String> paths)? prefetchFiles;
 
+  /// A function that returns true if the given file path is likely to be that
+  /// of a file that is generated.
+  final bool Function(String path)? isGenerated;
+
   final FileSystemStateTimers timers2 = FileSystemStateTimers();
 
   final FileSystemStateTestView testView = FileSystemStateTestView();
@@ -533,6 +537,7 @@
     this.featureSetProvider,
     this.getFileDigest,
     this.prefetchFiles,
+    this.isGenerated,
   );
 
   /// Update the state to reflect the fact that the file with the given [path]
@@ -662,6 +667,19 @@
     return file;
   }
 
+  /// Returns a list of files whose contents contains the given string.
+  /// Generated files are not included in the search.
+  List<String> getFilesContaining(String value) {
+    var result = <String>[];
+    _pathToFile.forEach((path, file) {
+      var genFile = isGenerated == null ? false : isGenerated!(path);
+      if (!genFile && file.getContent().contains(value)) {
+        result.add(path);
+      }
+    });
+    return result;
+  }
+
   String? getPathForUri(Uri uri) {
     var source = _sourceFactory.forUri2(uri);
     if (source == null) {
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index e7dff9b..c24aa37 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -18,10 +18,12 @@
 import 'package:analyzer/src/dart/analysis/feature_set_provider.dart';
 import 'package:analyzer/src/dart/analysis/performance_logger.dart';
 import 'package:analyzer/src/dart/analysis/results.dart';
+import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/micro/analysis_context.dart';
 import 'package:analyzer/src/dart/micro/cider_byte_store.dart';
 import 'package:analyzer/src/dart/micro/library_analyzer.dart';
 import 'package:analyzer/src/dart/micro/library_graph.dart';
+import 'package:analyzer/src/dart/micro/utils.dart';
 import 'package:analyzer/src/exception/exception.dart';
 import 'package:analyzer/src/generated/engine.dart' show AnalysisOptionsImpl;
 import 'package:analyzer/src/generated/source.dart';
@@ -36,11 +38,25 @@
 import 'package:analyzer/src/util/file_paths.dart' as file_paths;
 import 'package:analyzer/src/util/performance/operation_performance.dart';
 import 'package:analyzer/src/workspace/workspace.dart';
+import 'package:collection/collection.dart';
 import 'package:yaml/yaml.dart';
 
 const M = 1024 * 1024 /*1 MiB*/;
 const memoryCacheSize = 200 * M;
 
+class CiderSearchMatch {
+  final String path;
+  final List<int> offsets;
+
+  CiderSearchMatch(this.path, this.offsets);
+
+  @override
+  bool operator ==(Object object) =>
+      object is CiderSearchMatch &&
+      path == object.path &&
+      const ListEquality<int>().equals(offsets, object.offsets);
+}
+
 class FileContext {
   final AnalysisOptionsImpl analysisOptions;
   final FileState file;
@@ -54,13 +70,15 @@
   CiderByteStore byteStore;
   final SourceFactory sourceFactory;
 
-  /*
-   * A function that returns the digest for a file as a String. The function
-   * returns a non null value, can return an empty string if file does
-   * not exist/has no contents.
-   */
+  /// A function that returns the digest for a file as a String. The function
+  /// returns a non null value, can return an empty string if file does
+  /// not exist/has no contents.
   final String Function(String path) getFileDigest;
 
+  /// A function that returns true if the given file path is likely to be that
+  /// of a file that is generated.
+  final bool Function(String path)? isGenerated;
+
   /// A function that fetches the given list of files. This function can be used
   /// to batch file reads in systems where file fetches are expensive.
   final void Function(List<String> paths)? prefetchFiles;
@@ -96,6 +114,7 @@
     String Function(String path) getFileDigest,
     void Function(List<String> paths)? prefetchFiles, {
     required Workspace workspace,
+    bool Function(String path)? isGenerated,
     @deprecated Duration? libraryContextResetTimeout,
   }) : this.from(
           logger: logger,
@@ -104,6 +123,8 @@
           getFileDigest: getFileDigest,
           prefetchFiles: prefetchFiles,
           workspace: workspace,
+          isGenerated: isGenerated,
+
           // ignore: deprecated_member_use_from_same_package
           libraryContextResetTimeout: libraryContextResetTimeout,
         );
@@ -115,6 +136,7 @@
     required String Function(String path) getFileDigest,
     required void Function(List<String> paths)? prefetchFiles,
     required Workspace workspace,
+    bool Function(String path)? isGenerated,
     CiderByteStore? byteStore,
     @deprecated Duration? libraryContextResetTimeout,
   })  : logger = logger,
@@ -123,6 +145,7 @@
         getFileDigest = getFileDigest,
         prefetchFiles = prefetchFiles,
         workspace = workspace,
+        isGenerated = isGenerated,
         byteStore = byteStore ?? CiderCachedByteStore(memoryCacheSize);
 
   /// Update the resolver to reflect the fact that the file with the given
@@ -164,6 +187,31 @@
   @deprecated
   void dispose() {}
 
+  /// Looks for references to the Element at the given offset and path. All the
+  /// files currently cached by the resolver are searched, generated files are
+  /// ignored.
+  List<CiderSearchMatch> findReferences(int offset, String path,
+      {OperationPerformanceImpl? performance}) {
+    var references = <CiderSearchMatch>[];
+    var unit = resolve(path: path);
+    var node = NodeLocator(offset).searchWithin(unit.unit);
+    var element = getElementOfNode(node);
+    if (element != null) {
+      // TODO(keertip): check if element is named constructor.
+      var result = fsState!.getFilesContaining(element.displayName);
+      result.forEach((filePath) {
+        var resolved = resolve(path: filePath);
+        var collector = ReferencesCollector(element);
+        resolved.unit?.accept(collector);
+        var offsets = collector.offsets;
+        if (offsets.isNotEmpty) {
+          references.add(CiderSearchMatch(filePath, offsets));
+        }
+      });
+    }
+    return references;
+  }
+
   ErrorsResult getErrors({
     required String path,
     OperationPerformanceImpl? performance,
@@ -555,6 +603,7 @@
         featureSetProvider,
         getFileDigest,
         prefetchFiles,
+        isGenerated,
       );
     }
 
diff --git a/pkg/analyzer/lib/src/dart/micro/utils.dart b/pkg/analyzer/lib/src/dart/micro/utils.dart
new file mode 100644
index 0000000..9afec39b
--- /dev/null
+++ b/pkg/analyzer/lib/src/dart/micro/utils.dart
@@ -0,0 +1,176 @@
+// Copyright (c) 2021, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'package:analyzer/dart/ast/ast.dart';
+import 'package:analyzer/dart/ast/visitor.dart';
+import 'package:analyzer/dart/element/element.dart';
+import 'package:analyzer/src/dart/ast/element_locator.dart';
+
+/// Return the [Element] of the given [node], or `null` if [node] is `null` or
+/// does not have an element.
+Element? getElementOfNode(AstNode? node) {
+  if (node == null) {
+    return null;
+  }
+  if (node is SimpleIdentifier && node.parent is LibraryIdentifier) {
+    node = node.parent;
+  }
+  if (node is LibraryIdentifier) {
+    node = node.parent;
+  }
+  if (node is StringLiteral && node.parent is UriBasedDirective) {
+    return null;
+  }
+  var element = ElementLocator.locate(node);
+  if (node is SimpleIdentifier && element is PrefixElement) {
+    var parent = node.parent;
+    if (parent is ImportDirective) {
+      element = parent.element;
+    } else {
+      element = _getImportElementInfo(node);
+    }
+  }
+  return element;
+}
+
+/// Return the [ImportElement] that declared [prefix] and imports [element].
+///
+/// [libraryElement] - the [LibraryElement] where reference is.
+/// [prefix] - the import prefix, maybe `null`.
+/// [element] - the referenced element.
+/// [importElementsMap] - the cache of [Element]s imported by [ImportElement]s.
+ImportElement? _getImportElement(LibraryElement libraryElement, String prefix,
+    Element element, Map<ImportElement, Set<Element>> importElementsMap) {
+  if (element.enclosingElement is! CompilationUnitElement) {
+    return null;
+  }
+  var usedLibrary = element.library;
+  // find ImportElement that imports used library with used prefix
+  List<ImportElement>? candidates;
+  for (var importElement in libraryElement.imports) {
+    // required library
+    if (importElement.importedLibrary != usedLibrary) {
+      continue;
+    }
+    // required prefix
+    var prefixElement = importElement.prefix;
+    if (prefixElement == null) {
+      continue;
+    }
+    if (prefix != prefixElement.name) {
+      continue;
+    }
+    // no combinators => only possible candidate
+    if (importElement.combinators.isEmpty) {
+      return importElement;
+    }
+    // OK, we have candidate
+    candidates ??= [];
+    candidates.add(importElement);
+  }
+  // no candidates, probably element is defined in this library
+  if (candidates == null) {
+    return null;
+  }
+  // one candidate
+  if (candidates.length == 1) {
+    return candidates[0];
+  }
+  // ensure that each ImportElement has set of elements
+  for (var importElement in candidates) {
+    if (importElementsMap.containsKey(importElement)) {
+      continue;
+    }
+    var namespace = importElement.namespace;
+    var elements = Set<Element>.from(namespace.definedNames.values);
+    importElementsMap[importElement] = elements;
+  }
+  // use import namespace to choose correct one
+  for (var entry in importElementsMap.entries) {
+    var importElement = entry.key;
+    var elements = entry.value;
+    if (elements.contains(element)) {
+      return importElement;
+    }
+  }
+  // not found
+  return null;
+}
+
+/// Returns the [ImportElement] that is referenced by [prefixNode] with a
+/// [PrefixElement], maybe `null`.
+ImportElement? _getImportElementInfo(SimpleIdentifier prefixNode) {
+  // prepare environment
+  var parent = prefixNode.parent;
+  var unit = prefixNode.thisOrAncestorOfType<CompilationUnit>();
+  var libraryElement = unit?.declaredElement?.library;
+  if (libraryElement == null) {
+    return null;
+  }
+  // prepare used element
+  Element? usedElement;
+  if (parent is PrefixedIdentifier) {
+    var prefixed = parent;
+    if (prefixed.prefix == prefixNode) {
+      usedElement = prefixed.staticElement;
+    }
+  } else if (parent is MethodInvocation) {
+    var invocation = parent;
+    if (invocation.target == prefixNode) {
+      usedElement = invocation.methodName.staticElement;
+    }
+  }
+  // we need used Element
+  if (usedElement == null) {
+    return null;
+  }
+  // find ImportElement
+  var prefix = prefixNode.name;
+  var importElementsMap = <ImportElement, Set<Element>>{};
+  return _getImportElement(
+      libraryElement, prefix, usedElement, importElementsMap);
+}
+
+class ReferencesCollector extends GeneralizingAstVisitor<void> {
+  final Element element;
+  final List<int> offsets = [];
+
+  ReferencesCollector(this.element);
+
+  @override
+  void visitAssignmentExpression(AssignmentExpression node) {
+    if (node.writeElement != null &&
+        node.writeElement is PropertyAccessorElement) {
+      var property = node.writeElement as PropertyAccessorElement;
+      if (property.variable == element || property == element) {
+        if (node.leftHandSide is SimpleIdentifier) {
+          offsets.add(node.leftHandSide.offset);
+        } else if (node.leftHandSide is PrefixedIdentifier) {
+          var prefixIdentifier = node.leftHandSide as PrefixedIdentifier;
+          offsets.add(prefixIdentifier.identifier.offset);
+        } else if (node.leftHandSide is PropertyAccess) {
+          var accessor = node.leftHandSide as PropertyAccess;
+          offsets.add(accessor.propertyName.offset);
+        }
+      }
+    }
+    if (node.readElement != null &&
+        node.readElement is PropertyAccessorElement) {
+      var property = node.readElement as PropertyAccessorElement;
+      if (property.variable == element) {
+        offsets.add(node.rightHandSide.offset);
+      }
+    }
+  }
+
+  @override
+  void visitSimpleIdentifier(SimpleIdentifier node) {
+    var e = node.staticElement;
+    if (e == element) {
+      offsets.add(node.offset);
+    } else if (e is PropertyAccessorElement && e.variable == element) {
+      offsets.add(node.offset);
+    }
+  }
+}
diff --git a/pkg/analyzer/test/src/dart/micro/file_resolution.dart b/pkg/analyzer/test/src/dart/micro/file_resolution.dart
index 55d7031..ca6326b 100644
--- a/pkg/analyzer/test/src/dart/micro/file_resolution.dart
+++ b/pkg/analyzer/test/src/dart/micro/file_resolution.dart
@@ -54,6 +54,7 @@
       getFileDigest: (String path) => _getDigest(path),
       workspace: workspace,
       prefetchFiles: null,
+      isGenerated: null,
     );
     fileResolver.testView = FileResolverTestView();
   }
diff --git a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
index e82b7ca..a994e7d 100644
--- a/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
+++ b/pkg/analyzer/test/src/dart/micro/simple_file_resolver_test.dart
@@ -4,6 +4,7 @@
 
 import 'package:analyzer/src/dart/error/syntactic_errors.dart';
 import 'package:analyzer/src/dart/micro/cider_byte_store.dart';
+import 'package:analyzer/src/dart/micro/resolve_file.dart';
 import 'package:analyzer/src/error/codes.dart';
 import 'package:analyzer/src/lint/registry.dart';
 import 'package:test/test.dart';
@@ -346,6 +347,289 @@
         (fileResolver.byteStore as CiderCachedByteStore).testView!.length);
   }
 
+  test_findReferences_class() async {
+    var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+    newFile(aPath, content: r'''
+class A {
+  int foo;
+}
+''');
+
+    var bPath = convertPath('/workspace/dart/test/lib/b.dart');
+    newFile(bPath, content: r'''
+import 'a.dart';
+
+void func() {
+  var a = A();
+  print(a.foo);
+}
+''');
+
+    await resolveFile(bPath);
+    var result = fileResolver.findReferences(6, aPath);
+    var expected = <CiderSearchMatch>[
+      CiderSearchMatch(aPath, [6]),
+      CiderSearchMatch(bPath, [42])
+    ];
+    expect(result, unorderedEquals(expected));
+  }
+
+  test_findReferences_field() async {
+    var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+    newFile(aPath, content: r'''
+class A {
+  int foo = 0;
+
+  void func(int bar) {
+    foo = bar;
+ }
+}
+''');
+
+    await resolveFile(aPath);
+    var result = fileResolver.findReferences(16, aPath);
+    var expected = <CiderSearchMatch>[
+      CiderSearchMatch(aPath, [16, 53])
+    ];
+    expect(result, unorderedEquals(expected));
+  }
+
+  test_findReferences_function() async {
+    var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+    newFile(aPath, content: r'''
+main() {
+  foo('Hello');
+}
+
+foo(String str) {}
+''');
+
+    await resolveFile(aPath);
+    var result = fileResolver.findReferences(11, aPath);
+    var expected = <CiderSearchMatch>[
+      CiderSearchMatch(aPath, [11, 28])
+    ];
+    expect(result, unorderedEquals(expected));
+  }
+
+  test_findReferences_getter() async {
+    var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+    newFile(aPath, content: r'''
+class A {
+  int get foo => 6;
+}
+''');
+    var bPath = convertPath('/workspace/dart/test/lib/b.dart');
+    newFile(bPath, content: r'''
+import 'a.dart';
+
+main() {
+  var a = A();
+  var bar = a.foo;
+}
+''');
+
+    await resolveFile(bPath);
+    var result = fileResolver.findReferences(20, aPath);
+    var expected = <CiderSearchMatch>[
+      CiderSearchMatch(aPath, [20]),
+      CiderSearchMatch(bPath, [56])
+    ];
+    expect(result, unorderedEquals(expected));
+  }
+
+  test_findReferences_local_variable() async {
+    var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+    newFile(aPath, content: r'''
+class A {
+  void func(int n) {
+    var foo = bar+1;
+    print(foo);
+ }
+}
+''');
+    await resolveFile(aPath);
+    var result = fileResolver.findReferences(39, aPath);
+    var expected = <CiderSearchMatch>[
+      CiderSearchMatch(aPath, [39, 62])
+    ];
+    expect(result, unorderedEquals(expected));
+  }
+
+  test_findReferences_method() async {
+    var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+    newFile(aPath, content: r'''
+class A {
+  void func() {
+   print('hello');
+ }
+ 
+ void func2() {
+   func();
+ }
+}
+''');
+
+    var bPath = convertPath('/workspace/dart/test/lib/b.dart');
+    newFile(bPath, content: r'''
+import 'a.dart';
+
+main() {
+  var a = A();
+  a.func();
+}
+''');
+
+    await resolveFile(bPath);
+    var result = fileResolver.findReferences(17, aPath);
+    var expected = <CiderSearchMatch>[
+      CiderSearchMatch(aPath, [17, 69]),
+      CiderSearchMatch(bPath, [46])
+    ];
+    expect(result, unorderedEquals(expected));
+  }
+
+  test_findReferences_setter() async {
+    var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+    newFile(aPath, content: r'''
+class A {
+  void set value(int m){ };
+}
+''');
+    var bPath = convertPath('/workspace/dart/test/lib/b.dart');
+    newFile(bPath, content: r'''
+import 'a.dart';
+
+main() {
+  var a = A();
+  a.value = 6;
+}
+''');
+
+    await resolveFile(bPath);
+    var result = fileResolver.findReferences(21, aPath);
+    var expected = <CiderSearchMatch>[
+      CiderSearchMatch(aPath, [21]),
+      CiderSearchMatch(bPath, [46])
+    ];
+    expect(result, unorderedEquals(expected));
+  }
+
+  test_findReferences_top_level_getter() async {
+    var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+
+    newFile(aPath, content: r'''
+int _foo;
+
+int get foo => _foo;
+''');
+
+    var bPath = convertPath('/workspace/dart/test/lib/b.dart');
+    newFile(bPath, content: r'''
+import 'a.dart';
+
+main() {
+  var bar = foo;
+}
+''');
+
+    await resolveFile(bPath);
+    var result = fileResolver.findReferences(19, aPath);
+    var expected = <CiderSearchMatch>[
+      CiderSearchMatch(aPath, [19]),
+      CiderSearchMatch(bPath, [39])
+    ];
+    expect(result, unorderedEquals(expected));
+  }
+
+  test_findReferences_top_level_setter() async {
+    var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+
+    newFile(aPath, content: r'''
+int _foo;
+
+void set foo(int bar) { _foo = bar; }
+''');
+
+    var bPath = convertPath('/workspace/dart/test/lib/b.dart');
+    newFile(bPath, content: r'''
+import 'a.dart';
+
+main() {
+  foo = 6;
+}
+''');
+
+    await resolveFile(bPath);
+    var result = fileResolver.findReferences(20, aPath);
+    var expected = <CiderSearchMatch>[
+      CiderSearchMatch(aPath, [20]),
+      CiderSearchMatch(bPath, [29])
+    ];
+    expect(result, unorderedEquals(expected));
+  }
+
+  test_findReferences_top_level_variable() async {
+    var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+
+    newFile(aPath, content: r'''
+const int C = 42;
+
+void func() {
+    print(C);
+}
+''');
+
+    await resolveFile(aPath);
+    var result = fileResolver.findReferences(10, aPath);
+    var expected = <CiderSearchMatch>[
+      CiderSearchMatch(aPath, [10, 43])
+    ];
+    expect(result, unorderedEquals(expected));
+  }
+
+  test_findReferences_type_parameter() async {
+    var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+    newFile(aPath, content: r'''
+class Foo<T> {
+  List<T> l;
+  
+  void bar(T t) {}
+}
+''');
+    await resolveFile(aPath);
+    var result = fileResolver.findReferences(10, aPath);
+    var expected = <CiderSearchMatch>[
+      CiderSearchMatch(aPath, [10, 22, 42])
+    ];
+    expect(result.map((e) => e.path),
+        unorderedEquals(expected.map((e) => e.path)));
+    expect(result.map((e) => e.offsets),
+        unorderedEquals(expected.map((e) => e.offsets)));
+  }
+
+  test_findReferences_typedef() async {
+    var aPath = convertPath('/workspace/dart/test/lib/a.dart');
+    newFile(aPath, content: r'''
+typedef func = int Function(int);
+
+''');
+    var bPath = convertPath('/workspace/dart/test/lib/b.dart');
+    newFile(bPath, content: r'''
+import 'a.dart';
+
+void f(func o) {}
+''');
+
+    await resolveFile(bPath);
+    var result = fileResolver.findReferences(8, aPath);
+    var expected = <CiderSearchMatch>[
+      CiderSearchMatch(aPath, [8]),
+      CiderSearchMatch(bPath, [25])
+    ];
+    expect(result, unorderedEquals(expected));
+  }
+
   test_getErrors() {
     addTestFile(r'''
 var a = b;
diff --git a/tools/VERSION b/tools/VERSION
index 4cfe1b9..48a84ad 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -27,5 +27,5 @@
 MAJOR 2
 MINOR 14
 PATCH 0
-PRERELEASE 65
+PRERELEASE 66
 PRERELEASE_PATCH 0
\ No newline at end of file