Add rename constructor

Change-Id: Ie4815ed4b4db93cfad9307702fc86172685cfb17
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/242160
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Keerti Parthasarathy <keertip@google.com>
diff --git a/pkg/analysis_server/lib/src/cider/rename.dart b/pkg/analysis_server/lib/src/cider/rename.dart
index 33ba10e..a7ce3f3 100644
--- a/pkg/analysis_server/lib/src/cider/rename.dart
+++ b/pkg/analysis_server/lib/src/cider/rename.dart
@@ -2,15 +2,20 @@
 // 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:analysis_server/src/protocol_server.dart' hide Element;
 import 'package:analysis_server/src/services/correction/status.dart';
+import 'package:analysis_server/src/services/correction/util.dart';
 import 'package:analysis_server/src/services/refactoring/naming_conventions.dart';
 import 'package:analysis_server/src/services/refactoring/refactoring.dart';
+import 'package:analysis_server/src/services/search/hierarchy.dart';
 import 'package:analysis_server/src/utilities/flutter.dart';
+import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/source/line_info.dart';
 import 'package:analyzer/src/dart/ast/utilities.dart';
 import 'package:analyzer/src/dart/micro/resolve_file.dart';
 import 'package:analyzer/src/dart/micro/utils.dart';
+import 'package:analyzer/src/generated/java_core.dart';
 import 'package:analyzer/src/utilities/extensions/collection.dart';
 
 class CanRenameResponse {
@@ -45,12 +50,31 @@
       status = validateTypeAliasName(name);
     } else if (element is ClassElement) {
       status = validateClassName(name);
+    } else if (element is ConstructorElement) {
+      status = validateConstructorName(name);
+      _analyzePossibleConflicts(element, status, name);
     }
 
     if (status == null) {
       return null;
     }
-    return CheckNameResponse(status, this);
+    return CheckNameResponse(status, this, name);
+  }
+
+  void _analyzePossibleConflicts(
+      ConstructorElement element, RefactoringStatus result, String newName) {
+    var parentClass = element.enclosingElement;
+    // Check if the "newName" is the name of the enclosing class.
+    if (parentClass.name == newName) {
+      result.addError('The constructor should not have the same name '
+          'as the name of the enclosing class.');
+    }
+    // check if there are members with "newName" in the same ClassElement
+    for (var newNameMember in getChildren(parentClass, newName)) {
+      var message = format("Class '{0}' already declares {1} with name '{2}'.",
+          parentClass.displayName, getElementKindName(newNameMember), newName);
+      result.addError(message, newLocation_fromElement(newNameMember));
+    }
   }
 
   FlutterWidgetState? _findFlutterStateClass(Element element, String newName) {
@@ -76,8 +100,9 @@
 class CheckNameResponse {
   final RefactoringStatus status;
   final CanRenameResponse canRename;
+  final String newName;
 
-  CheckNameResponse(this.status, this.canRename);
+  CheckNameResponse(this.status, this.canRename, this.newName);
 
   LineInfo get lineInfo => canRename.lineInfo;
 
@@ -100,13 +125,148 @@
     for (var element in elements) {
       matches.addAll(await fileResolver.findReferences2(element));
     }
+
     FlutterWidgetRename? flutterRename;
-    if (canRename._flutterWidgetState != null) {
-      var stateWidget = canRename._flutterWidgetState!;
-      var match = await fileResolver.findReferences2(stateWidget.state);
-      flutterRename = FlutterWidgetRename(stateWidget.newName, match);
+    var flutterState = canRename._flutterWidgetState;
+    if (flutterState != null) {
+      var stateClass = flutterState.state;
+      var stateName = flutterState.newName;
+      var match = await fileResolver.findReferences2(stateClass);
+      var sourcePath = stateClass.source.fullName;
+      var location = stateClass.enclosingElement.lineInfo
+          .getLocation(stateClass.nameOffset);
+      CiderSearchMatch ciderMatch;
+      var searchInfo = CiderSearchInfo(
+          location, stateClass.nameLength, MatchKind.DECLARATION);
+      try {
+        ciderMatch = match.firstWhere((m) => m.path == sourcePath);
+        ciderMatch.references.add(searchInfo);
+      } catch (_) {
+        match.add(CiderSearchMatch(sourcePath, [], [searchInfo]));
+      }
+      var replacements = match
+          .map((m) => CiderReplaceMatch(
+              m.path,
+              m.references
+                  .map((p) => ReplaceInfo(
+                      stateName, p.startPosition, stateClass.nameLength))
+                  .toList()))
+          .toList();
+      flutterRename = FlutterWidgetRename(stateName, match, replacements);
     }
-    return RenameResponse(matches, this, flutterWidgetRename: flutterRename);
+    var replaceMatches = <CiderReplaceMatch>[];
+    if (element is ConstructorElement) {
+      for (var match in matches) {
+        var replaceInfo = <ReplaceInfo>[];
+        for (var ref in match.references) {
+          String replacement = newName.isNotEmpty ? '.$newName' : '';
+          if (replacement.isEmpty &&
+              ref.kind == MatchKind.REFERENCE_BY_CONSTRUCTOR_TEAR_OFF) {
+            replacement = '.new';
+          }
+          if (ref.kind ==
+              MatchKind.INVOCATION_BY_ENUM_CONSTANT_WITHOUT_ARGUMENTS) {
+            replacement += '()';
+          }
+          replaceInfo
+              .add(ReplaceInfo(replacement, ref.startPosition, ref.length));
+        }
+        replaceMatches.addMatch(match.path, replaceInfo);
+      }
+      if (element.isSynthetic) {
+        var result = await _replaceSyntheticConstructor();
+        if (result != null) {
+          replaceMatches.addMatch(result.path, result.matches.toList());
+        }
+      }
+    } else {
+      for (var match in matches) {
+        replaceMatches.addMatch(
+            match.path,
+            match.references
+                .map((info) =>
+                    ReplaceInfo(newName, info.startPosition, info.length))
+                .toList());
+      }
+      // add element declaration
+      var sourcePath = element.source!.fullName;
+      var infos = await _addElementDeclaration(element, sourcePath);
+      replaceMatches.addMatch(sourcePath, infos);
+    }
+    return RenameResponse(matches, this, replaceMatches,
+        flutterWidgetRename: flutterRename);
+  }
+
+  Future<List<ReplaceInfo>> _addElementDeclaration(
+      Element element, String sourcePath) async {
+    var infos = <ReplaceInfo>[];
+    if (element is PropertyInducingElement && element.isSynthetic) {
+      if (element.getter != null) {
+        infos.add(ReplaceInfo(
+            newName,
+            lineInfo.getLocation(element.getter!.nameOffset),
+            element.getter!.nameLength));
+      }
+      if (element.setter != null) {
+        infos.add(ReplaceInfo(
+            newName,
+            lineInfo.getLocation(element.setter!.nameOffset),
+            element.setter!.nameLength));
+      }
+    } else {
+      var location = (await canRename._fileResolver.resolve2(path: sourcePath))
+          .lineInfo
+          .getLocation(element.nameOffset);
+      infos.add(ReplaceInfo(newName, location, element.nameLength));
+    }
+    return infos;
+  }
+
+  Future<CiderReplaceMatch?> _replaceSyntheticConstructor() async {
+    var element = canRename.refactoringElement.element;
+    var classElement = element.enclosingElement;
+
+    var fileResolver = canRename._fileResolver;
+    var libraryPath = classElement!.library!.source.fullName;
+    var resolvedLibrary = await fileResolver.resolveLibrary2(path: libraryPath);
+    var result = resolvedLibrary.getElementDeclaration(classElement);
+    if (result == null) {
+      return null;
+    }
+
+    var resolvedUnit = result.resolvedUnit;
+    if (resolvedUnit == null) {
+      return null;
+    }
+
+    var node = result.node;
+    if (node is ClassDeclaration) {
+      var utils = CorrectionUtils(resolvedUnit);
+      var location = utils.prepareNewConstructorLocation(
+          fileResolver.contextObjects!.analysisSession, node);
+      if (location == null) {
+        return null;
+      }
+
+      var header = '${classElement.name}.$newName();';
+      return CiderReplaceMatch(libraryPath, [
+        ReplaceInfo(location.prefix + header + location.suffix,
+            resolvedUnit.lineInfo.getLocation(location.offset), 0)
+      ]);
+    } else if (node is EnumDeclaration) {
+      var utils = CorrectionUtils(resolvedUnit);
+      var location = utils.prepareEnumNewConstructorLocation(node);
+      if (location == null) {
+        return null;
+      }
+
+      var header = 'const ${classElement.name}.$newName();';
+      return CiderReplaceMatch(libraryPath, [
+        ReplaceInfo(location.prefix + header + location.suffix,
+            resolvedUnit.lineInfo.getLocation(location.offset), 0)
+      ]);
+    }
+    return null;
   }
 }
 
@@ -151,7 +311,7 @@
   bool _canRenameElement(Element element) {
     var enclosingElement = element.enclosingElement;
     if (element is ConstructorElement) {
-      return false;
+      return true;
     }
     if (element is LabelElement || element is LocalElement) {
       return true;
@@ -161,16 +321,24 @@
         enclosingElement is CompilationUnitElement) {
       return true;
     }
-
     return false;
   }
 }
 
+class CiderReplaceMatch {
+  final String path;
+  List<ReplaceInfo> matches;
+
+  CiderReplaceMatch(this.path, this.matches);
+}
+
 class FlutterWidgetRename {
   final String name;
+  @deprecated
   final List<CiderSearchMatch> matches;
+  final List<CiderReplaceMatch> replacements;
 
-  FlutterWidgetRename(this.name, this.matches);
+  FlutterWidgetRename(this.name, this.matches, this.replacements);
 }
 
 /// The corresponding `State` declaration of a  Flutter `StatefulWidget`.
@@ -182,9 +350,39 @@
 }
 
 class RenameResponse {
+  @deprecated
   final List<CiderSearchMatch> matches;
   final CheckNameResponse checkName;
+  final List<CiderReplaceMatch> replaceMatches;
   FlutterWidgetRename? flutterWidgetRename;
 
-  RenameResponse(this.matches, this.checkName, {this.flutterWidgetRename});
+  RenameResponse(this.matches, this.checkName, this.replaceMatches,
+      {this.flutterWidgetRename});
+}
+
+class ReplaceInfo {
+  final String replacementText;
+  final CharacterLocation startPosition;
+  final int length;
+
+  ReplaceInfo(this.replacementText, this.startPosition, this.length);
+
+  @override
+  bool operator ==(Object other) =>
+      other is ReplaceInfo &&
+      replacementText == other.replacementText &&
+      startPosition == other.startPosition &&
+      length == other.length;
+}
+
+extension on List<CiderReplaceMatch> {
+  void addMatch(String path, List<ReplaceInfo> infos) {
+    for (var m in this) {
+      if (m.path == path) {
+        m.matches.addAll(infos);
+        return;
+      }
+    }
+    add(CiderReplaceMatch(path, infos));
+  }
 }
diff --git a/pkg/analysis_server/test/src/cider/rename_test.dart b/pkg/analysis_server/test/src/cider/rename_test.dart
index 4adefd9..3a3ec88 100644
--- a/pkg/analysis_server/test/src/cider/rename_test.dart
+++ b/pkg/analysis_server/test/src/cider/rename_test.dart
@@ -4,7 +4,7 @@
 
 import 'package:analysis_server/src/cider/rename.dart';
 import 'package:analyzer/source/line_info.dart';
-import 'package:analyzer/src/dart/micro/resolve_file.dart';
+import 'package:analyzer_plugin/protocol/protocol_common.dart';
 import 'package:test/test.dart';
 import 'package:test_reflective_loader/test_reflective_loader.dart';
 
@@ -20,6 +20,8 @@
 @reflectiveTest
 class CiderRenameComputerTest extends CiderServiceTest {
   late _CorrectionContext _correctionContext;
+  late LineInfo? _lineInfo;
+  late String _testCode;
 
   @override
   void setUp() {
@@ -27,6 +29,16 @@
     BazelMockPackages.instance.addFlutter(resourceProvider);
   }
 
+  void test_cannotRename_inSdk() async {
+    var refactor = await _compute(r'''
+main() {
+  new String.^fromCharCodes([]);
+}
+''');
+
+    expect(refactor, isNull);
+  }
+
   void test_canRename_class() async {
     var refactor = await _compute(r'''
 class ^Old {}
@@ -173,6 +185,17 @@
     expect(result.oldName, 'a');
   }
 
+  void test_checkName_newName() async {
+    var result = await _checkName(r'''
+class A {
+  A.^test() {}
+}
+''', 'test');
+
+    expect(result!.status.problems.length, 1);
+    expect(result.status.hasError, isTrue);
+  }
+
   void test_checkName_parameter() async {
     var result = await _checkName(r'''
 void foo(String ^a) {
@@ -203,7 +226,7 @@
   }
 
   void test_rename_class() async {
-    var result = await _rename(r'''
+    var testCode = '''
 class ^Old implements Other {
   Old() {}
   Old.named() {}
@@ -216,26 +239,26 @@
   Old t1 = new Old();
   Old t2 = new Old.named();
 }
-''', 'New');
-
-    expect(result!.matches.length, 1);
-    expect(result.matches, [
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'), [
-        CharacterLocation(1, 7),
-        CharacterLocation(2, 3),
-        CharacterLocation(3, 3),
-        CharacterLocation(6, 23),
-        CharacterLocation(7, 23),
-        CharacterLocation(10, 3),
-        CharacterLocation(10, 16),
-        CharacterLocation(11, 3),
-        CharacterLocation(11, 16)
-      ])
-    ]);
+''';
+    var result = await _rename(testCode, 'New');
+    _assertTestChangeResult('''
+class New implements Other {
+  New() {}
+  New.named() {}
+}
+class Other {
+  factory Other.a() = New;
+  factory Other.b() = New.named;
+}
+void f() {
+  New t1 = new New();
+  New t2 = new New.named();
+}
+''', result!.replaceMatches.first.matches);
   }
 
   void test_rename_class_flutterWidget() async {
-    var result = await _rename(r'''
+    var testCode = '''
 import 'package:flutter/material.dart';
 
 class ^TestPage extends StatefulWidget {
@@ -249,27 +272,299 @@
   @override
   Widget build(BuildContext context) => throw 0;
 }
-''', 'NewPage');
+''';
 
-    expect(result!.matches.length, 1);
-    expect(result.matches, [
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'), [
-        CharacterLocation(3, 7),
-        CharacterLocation(4, 9),
-        CharacterLocation(7, 9),
-        CharacterLocation(10, 35)
-      ])
+    var result = await _rename(testCode, 'NewPage');
+    expect(result!.replaceMatches.length, 1);
+    expect(result.replaceMatches.first.matches, [
+      ReplaceInfo('NewPage', CharacterLocation(4, 9), 8),
+      ReplaceInfo('NewPage', CharacterLocation(7, 9), 8),
+      ReplaceInfo('NewPage', CharacterLocation(10, 35), 8),
+      ReplaceInfo('NewPage', CharacterLocation(3, 7), 8)
     ]);
     expect(result.flutterWidgetRename != null, isTrue);
     expect(result.flutterWidgetRename!.name, 'NewPageState');
-    expect(result.flutterWidgetRename!.matches, [
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'),
-          [CharacterLocation(7, 36), CharacterLocation(10, 7)])
-    ]);
+    expect(
+        result.flutterWidgetRename!.replacements.first.matches
+            .map((m) => m.startPosition)
+            .toList(),
+        [CharacterLocation(7, 36), CharacterLocation(10, 7)]);
+  }
+
+  void test_rename_constructor_add() async {
+    var testCode = '''
+// ignore: deprecated_new_in_comment_reference
+/// Documentation for [new A] and [A.new]
+class A {
+  ^A() {} // marker
+  factory A._() = A;
+}
+class B extends A {
+  B() : super() {}
+}
+main() {
+  new A();
+  A.new;
+}
+''';
+
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult('''
+// ignore: deprecated_new_in_comment_reference
+/// Documentation for [new A.newName] and [A.newName]
+class A {
+  A.newName() {} // marker
+  factory A._() = A.newName;
+}
+class B extends A {
+  B() : super.newName() {}
+}
+main() {
+  new A.newName();
+  A.newName;
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_constructor_enum() async {
+    var testCode = '''
+/// [E.new]
+enum E {
+  v1(), v2.new(), v3, v4.other();
+  const ^E(); // 0
+  const E.other() : this();
+}
+''';
+
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult('''
+/// [E.newName]
+enum E {
+  v1.newName(), v2.newName(), v3.newName(), v4.other();
+  const E.newName(); // 0
+  const E.other() : this.newName();
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_constructor_enum_hasConstructor() async {
+    var testCode = '''
+/// [E.new]
+enum E {
+  v1(), v2.^new(), v3;
+
+  factory E.other() => throw 0;
+}
+''';
+
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult('''
+/// [E.newName]
+enum E {
+  v1.newName(), v2.newName(), v3.newName();
+
+  factory E.other() => throw 0;
+
+  const E.newName();
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_constructor_enum_hasField() async {
+    var testCode = '''
+/// [E.new]
+enum E {
+  v1(), v2.^new(), v3;
+
+  final int foo = 0;
+}
+''';
+
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult('''
+/// [E.newName]
+enum E {
+  v1.newName(), v2.newName(), v3.newName();
+
+  final int foo = 0;
+
+  const E.newName();
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_constructor_enum_hasMethod() async {
+    var testCode = '''
+/// [E.new]
+enum E {
+  v1(), v2.^new(), v3;
+
+  void foo() {}
+}
+''';
+
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult('''
+/// [E.newName]
+enum E {
+  v1.newName(), v2.newName(), v3.newName();
+
+  const E.newName();
+
+  void foo() {}
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_constructor_enum_named() async {
+    var testCode = '''
+/// [E.test]
+enum E {
+  v1.^test(), v2.other();
+  const E.test(); // 0
+  const E.other() : this.test();
+}
+''';
+
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult('''
+/// [E.newName]
+enum E {
+  v1.newName(), v2.other();
+  const E.newName(); // 0
+  const E.other() : this.newName();
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_constructor_enum_remove() async {
+    var testCode = '''
+/// [E]
+enum E {
+  v1.test(), v2.other();
+  const E.^test(); // 0
+  const E.other() : this.test();
+}
+''';
+
+    var result = await _rename(testCode, '');
+    _assertTestChangeResult('''
+/// [E]
+enum E {
+  v1(), v2.other();
+  const E(); // 0
+  const E.other() : this();
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_constructor_named() async {
+    var testCode = '''
+// ignore: deprecated_new_in_comment_reference
+/// Documentation for [A.test] and [new A.test]
+class A {
+  A.^test() {} // marker
+  factory A._() = A.test;
+}
+class B extends A {
+  B() : super.test() {}
+}
+main() {
+  new A.test();
+  A.test;
+}
+''';
+
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult('''
+// ignore: deprecated_new_in_comment_reference
+/// Documentation for [A.newName] and [new A.newName]
+class A {
+  A.newName() {} // marker
+  factory A._() = A.newName;
+}
+class B extends A {
+  B() : super.newName() {}
+}
+main() {
+  new A.newName();
+  A.newName;
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_constructor_remove() async {
+    var testCode = '''
+// ignore: deprecated_new_in_comment_reference
+/// Documentation for [A.test] and [new A.test]
+class A {
+  A.^test() {} // marker
+  factory A._() = A.test;
+}
+class B extends A {
+  B() : super.test() {}
+}
+main() {
+  new A.test();
+  A.test;
+}
+''';
+
+    var result = await _rename(testCode, '');
+    _assertTestChangeResult('''
+// ignore: deprecated_new_in_comment_reference
+/// Documentation for [A] and [new A]
+class A {
+  A() {} // marker
+  factory A._() = A;
+}
+class B extends A {
+  B() : super() {}
+}
+main() {
+  new A();
+  A.new;
+}
+''', result!.replaceMatches.first.matches);
+  }
+
+  void test_rename_constructor_synthetic() async {
+    var testCode = '''
+// ignore: deprecated_new_in_comment_reference
+/// Documentation for [new A] and [A.new]
+class A {
+  int field = 0;
+}
+class B extends A {
+  B() : super() {}
+}
+main() {
+  new A();
+  A.^new;
+}
+''';
+
+    var result = await _rename(testCode, 'newName');
+    _assertTestChangeResult('''
+// ignore: deprecated_new_in_comment_reference
+/// Documentation for [new A.newName] and [A.newName]
+class A {
+  int field = 0;
+
+  A.newName();
+}
+class B extends A {
+  B() : super.newName() {}
+}
+main() {
+  new A.newName();
+  A.newName;
+}
+''', result!.replaceMatches.first.matches);
   }
 
   void test_rename_field() async {
-    var result = await _rename(r'''
+    var testCode = '''
 class A{
   int get ^x => 5;
 }
@@ -277,17 +572,22 @@
 void foo() {
   var m = A().x;
 }
-''', 'y');
+''';
 
-    expect(result, isNotNull);
-    expect(result!.matches, [
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'),
-          [CharacterLocation(2, 11), CharacterLocation(6, 15)]),
-    ]);
+    var result = await _rename(testCode, 'y');
+    _assertTestChangeResult('''
+class A{
+  int get y => 5;
+}
+
+void foo() {
+  var m = A().y;
+}
+''', result!.replaceMatches.first.matches);
   }
 
   void test_rename_field_static_private() async {
-    var result = await _rename(r'''
+    var testCode = '''
 class A{
   static const ^_val = 1234;
 }
@@ -295,17 +595,22 @@
 void foo() {
   print(A._val);
 }
-''', '_newVal');
+''';
 
-    expect(result, isNotNull);
-    expect(result!.matches, [
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'),
-          [CharacterLocation(2, 16), CharacterLocation(6, 11)]),
-    ]);
+    var result = await _rename(testCode, '_newVal');
+    _assertTestChangeResult('''
+class A{
+  static const _newVal = 1234;
+}
+
+void foo() {
+  print(A._newVal);
+}
+''', result!.replaceMatches.first.matches);
   }
 
   void test_rename_function() async {
-    var result = await _rename(r'''
+    var testCode = '''
 test() {}
 ^foo() {}
 void f() {
@@ -313,15 +618,18 @@
   print(test());
   foo();
 }
-''', 'bar');
+''';
 
-    expect(result!.matches.length, 1);
-    expect(result.matches, [
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'), [
-        CharacterLocation(2, 1),
-        CharacterLocation(6, 3),
-      ])
-    ]);
+    var result = await _rename(testCode, 'bar');
+    _assertTestChangeResult('''
+test() {}
+bar() {}
+void f() {
+  print(test);
+  print(test());
+  bar();
+}
+''', result!.replaceMatches.first.matches);
   }
 
   void test_rename_function_imported() async {
@@ -335,28 +643,27 @@
   ^foo();
 }
 ''', 'bar');
-    expect(result!.matches.length, 2);
-    expect(result.matches, [
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/a.dart'), [
-        CharacterLocation(1, 1),
-      ]),
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'),
-          [CharacterLocation(3, 3)])
-    ]);
+
+    expect(result!.replaceMatches.length, 2);
+    expect(result.replaceMatches.first.matches,
+        [ReplaceInfo('bar', CharacterLocation(3, 3), 3)]);
+    expect(result.replaceMatches[1].matches,
+        [ReplaceInfo('bar', CharacterLocation(1, 1), 3)]);
   }
 
   void test_rename_local() async {
-    var result = await _rename(r'''
+    var testCode = '''
 void foo() {
   var ^a = 0; var b = a + 1;
 }
-''', 'bar');
+''';
 
-    expect(result!.matches.length, 1);
-    expect(
-        result.matches[0],
-        CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'),
-            [CharacterLocation(2, 7), CharacterLocation(2, 22)]));
+    var result = await _rename(testCode, 'bar');
+    _assertTestChangeResult('''
+void foo() {
+  var bar = 0; var b = bar + 1;
+}
+''', result!.replaceMatches.first.matches);
   }
 
   void test_rename_method_imported() async {
@@ -372,56 +679,76 @@
   var a = A().^foo();
 }
 ''', 'bar');
-    expect(result!.matches.length, 2);
-    expect(result.matches, [
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/a.dart'), [
-        CharacterLocation(2, 3),
-      ]),
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'),
-          [CharacterLocation(3, 15)])
-    ]);
+    expect(result!.replaceMatches.length, 2);
+    expect(result.replaceMatches.first.matches,
+        [ReplaceInfo('bar', CharacterLocation(3, 15), 3)]);
+    expect(result.replaceMatches[1].matches,
+        [ReplaceInfo('bar', CharacterLocation(2, 3), 3)]);
   }
 
   void test_rename_parameter() async {
-    var result = await _rename(r'''
+    var testCode = '''
 void foo(String ^a) {
   var b = a + 1;
 }
-''', 'bar');
-    expect(result!.matches.length, 1);
-    expect(result.checkName.oldName, 'a');
+''';
+    var result = await _rename(testCode, 'bar');
+    _assertTestChangeResult('''
+void foo(String bar) {
+  var b = bar + 1;
+}
+''', result!.replaceMatches.first.matches);
   }
 
   void test_rename_propertyAccessor() async {
-    var result = await _rename(r'''
+    var testCode = '''
 get foo {}
 set foo(x) {}
 void f() {
   print(foo);
   ^foo = 1;
   foo += 2;
-''', 'bar');
-    expect(result!.matches, [
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'),
-          [CharacterLocation(1, 5), CharacterLocation(4, 9)]),
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'), [
-        CharacterLocation(2, 5),
-        CharacterLocation(5, 3),
-        CharacterLocation(6, 3)
-      ])
-    ]);
+''';
+    var result = await _rename(testCode, 'bar');
+    _assertTestChangeResult('''
+get bar {}
+set bar(x) {}
+void f() {
+  print(bar);
+  bar = 1;
+  bar += 2;
+''', result!.replaceMatches.first.matches);
   }
 
   void test_rename_typeAlias_functionType() async {
-    var result = await _rename(r'''
+    var testCode = '''
 typedef ^F = void Function();
 void f(F a) {}
-''', 'bar');
+''';
 
-    expect(result!.matches, [
-      CiderSearchMatch(convertPath('/workspace/dart/test/lib/test.dart'),
-          [CharacterLocation(1, 9), CharacterLocation(2, 8)])
-    ]);
+    var result = await _rename(testCode, 'bar');
+    _assertTestChangeResult('''
+typedef bar = void Function();
+void f(bar a) {}
+''', result!.replaceMatches.first.matches);
+  }
+
+  // Asserts that the results of the rename is the [expectedCode].
+  void _assertTestChangeResult(
+      String expectedCode, List<ReplaceInfo> changes) async {
+    var edits = <SourceEdit>[];
+    for (var change in changes) {
+      var offset =
+          _lineInfo!.getOffsetOfLine(change.startPosition.lineNumber - 1) +
+              change.startPosition.columnNumber -
+              1;
+      edits.add(SourceEdit(offset, change.length, change.replacementText));
+    }
+    edits.sort((a, b) => a.offset.compareTo(b.offset));
+    edits = edits.reversed.toList();
+    // validate resulting code
+    var actualCode = SourceEdit.applySequence(_testCode, edits);
+    expect(actualCode, expectedCode);
   }
 
   Future<CheckNameResponse?> _checkName(String content, String newName) async {
@@ -459,6 +786,7 @@
       _correctionContext.line,
       _correctionContext.character,
     );
+    _lineInfo = canRename?.lineInfo;
     return canRename?.checkNewName(newName)?.computeRenameRanges2();
   }
 
@@ -470,8 +798,8 @@
     var lineInfo = LineInfo.fromContent(content);
     var location = lineInfo.getLocation(offset);
 
-    content = content.substring(0, offset) + content.substring(offset + 1);
-    newFile(testPath, content);
+    _testCode = content.substring(0, offset) + content.substring(offset + 1);
+    newFile(testPath, _testCode);
 
     _correctionContext = _CorrectionContext(
       content,
diff --git a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
index 989c73c..e333fc8 100644
--- a/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
+++ b/pkg/analyzer/lib/src/dart/micro/resolve_file.dart
@@ -44,21 +44,42 @@
 const M = 1024 * 1024 /*1 MiB*/;
 const memoryCacheSize = 200 * M;
 
+class CiderSearchInfo {
+  final CharacterLocation startPosition;
+  final int length;
+  final MatchKind kind;
+
+  CiderSearchInfo(this.startPosition, this.length, this.kind);
+
+  @override
+  bool operator ==(Object other) =>
+      other is CiderSearchInfo &&
+      startPosition == other.startPosition &&
+      length == other.length &&
+      kind == other.kind;
+}
+
 class CiderSearchMatch {
   final String path;
+  @deprecated
   final List<CharacterLocation?> startPositions;
+  final List<CiderSearchInfo> references;
 
-  CiderSearchMatch(this.path, this.startPositions);
+  CiderSearchMatch(this.path, this.startPositions, this.references);
 
   @override
   bool operator ==(Object other) =>
       other is CiderSearchMatch &&
       path == other.path &&
       const ListEquality<CharacterLocation?>()
-          .equals(startPositions, other.startPositions);
+          // ignore: deprecated_member_use_from_same_package
+          .equals(startPositions, other.startPositions) &&
+      const ListEquality<CiderSearchInfo>()
+          .equals(references, other.references);
 
   @override
   String toString() {
+    // ignore: deprecated_member_use_from_same_package
     return '($path, $startPositions)';
   }
 }
@@ -191,13 +212,19 @@
           var resolved = await resolve2(path: path);
           var collector = ReferencesCollector(element);
           resolved.unit.accept(collector);
-          var offsets = collector.offsets;
-          if (offsets.isNotEmpty) {
+          var matches = collector.references;
+          if (matches.isNotEmpty) {
             var lineInfo = resolved.unit.lineInfo;
             references.add(CiderSearchMatch(
                 path,
-                offsets
-                    .map((offset) => lineInfo.getLocation(offset))
+                matches
+                    .map((match) => lineInfo.getLocation(match.offset))
+                    .toList(),
+                matches
+                    .map((match) => CiderSearchInfo(
+                        lineInfo.getLocation(match.offset),
+                        match.length,
+                        match.matchKind))
                     .toList()));
           }
         });
diff --git a/pkg/analyzer/lib/src/dart/micro/utils.dart b/pkg/analyzer/lib/src/dart/micro/utils.dart
index 9afec39b..6908497 100644
--- a/pkg/analyzer/lib/src/dart/micro/utils.dart
+++ b/pkg/analyzer/lib/src/dart/micro/utils.dart
@@ -6,6 +6,8 @@
 import 'package:analyzer/dart/ast/visitor.dart';
 import 'package:analyzer/dart/element/element.dart';
 import 'package:analyzer/src/dart/ast/element_locator.dart';
+import 'package:analyzer/src/dart/element/element.dart';
+import 'package:collection/src/iterable_extensions.dart';
 
 /// Return the [Element] of the given [node], or `null` if [node] is `null` or
 /// does not have an element.
@@ -34,6 +36,32 @@
   return element;
 }
 
+/// If the given [constructor] is a synthetic constructor created for a
+/// [ClassTypeAlias], return the actual constructor of a [ClassDeclaration]
+/// which is invoked.  Return `null` if a redirection cycle is detected.
+ConstructorElement? _getActualConstructorElement(
+    ConstructorElement? constructor) {
+  var seenConstructors = <ConstructorElement?>{};
+  while (constructor is ConstructorElementImpl && constructor.isSynthetic) {
+    var enclosing = constructor.enclosingElement;
+    if (enclosing.isMixinApplication) {
+      var superInvocation = constructor.constantInitializers
+          .whereType<SuperConstructorInvocation>()
+          .singleOrNull;
+      if (superInvocation != null) {
+        constructor = superInvocation.staticElement;
+      }
+    } else {
+      break;
+    }
+    // fail if a cycle is detected
+    if (!seenConstructors.add(constructor)) {
+      return null;
+    }
+  }
+  return constructor;
+}
+
 /// Return the [ImportElement] that declared [prefix] and imports [element].
 ///
 /// [libraryElement] - the [LibraryElement] where reference is.
@@ -132,9 +160,55 @@
       libraryElement, prefix, usedElement, importElementsMap);
 }
 
+class MatchInfo {
+  final int offset;
+  final int length;
+  final MatchKind matchKind;
+
+  MatchInfo(this.offset, this.length, this.matchKind);
+}
+
+/// Instances of the enum [MatchKind] represent the kind of reference that was
+/// found when a match represents a reference to an element.
+class MatchKind {
+  /// A declaration of an element.
+  static const MatchKind DECLARATION = MatchKind('DECLARATION');
+
+  /// A reference to an element in which it is being read.
+  static const MatchKind READ = MatchKind('READ');
+
+  /// A reference to an element in which it is being both read and written.
+  static const MatchKind READ_WRITE = MatchKind('READ_WRITE');
+
+  /// A reference to an element in which it is being written.
+  static const MatchKind WRITE = MatchKind('WRITE');
+
+  /// A reference to an element in which it is being invoked.
+  static const MatchKind INVOCATION = MatchKind('INVOCATION');
+
+  /// An invocation of an enum constructor from an enum constant without
+  /// arguments.
+  static const MatchKind INVOCATION_BY_ENUM_CONSTANT_WITHOUT_ARGUMENTS =
+      MatchKind('INVOCATION_BY_ENUM_CONSTANT_WITHOUT_ARGUMENTS');
+
+  /// A reference to an element in which it is referenced.
+  static const MatchKind REFERENCE = MatchKind('REFERENCE');
+
+  /// A tear-off reference to a constructor.
+  static const MatchKind REFERENCE_BY_CONSTRUCTOR_TEAR_OFF =
+      MatchKind('REFERENCE_BY_CONSTRUCTOR_TEAR_OFF');
+
+  final String name;
+
+  const MatchKind(this.name);
+
+  @override
+  String toString() => name;
+}
+
 class ReferencesCollector extends GeneralizingAstVisitor<void> {
   final Element element;
-  final List<int> offsets = [];
+  final List<MatchInfo> references = [];
 
   ReferencesCollector(this.element);
 
@@ -142,16 +216,20 @@
   void visitAssignmentExpression(AssignmentExpression node) {
     if (node.writeElement != null &&
         node.writeElement is PropertyAccessorElement) {
+      var kind = MatchKind.WRITE;
       var property = node.writeElement as PropertyAccessorElement;
       if (property.variable == element || property == element) {
         if (node.leftHandSide is SimpleIdentifier) {
-          offsets.add(node.leftHandSide.offset);
+          references.add(MatchInfo(
+              node.leftHandSide.offset, node.leftHandSide.length, kind));
         } else if (node.leftHandSide is PrefixedIdentifier) {
           var prefixIdentifier = node.leftHandSide as PrefixedIdentifier;
-          offsets.add(prefixIdentifier.identifier.offset);
+          references.add(MatchInfo(prefixIdentifier.identifier.offset,
+              prefixIdentifier.identifier.length, kind));
         } else if (node.leftHandSide is PropertyAccess) {
           var accessor = node.leftHandSide as PropertyAccess;
-          offsets.add(accessor.propertyName.offset);
+          references.add(
+              MatchInfo(accessor.propertyName.offset, accessor.length, kind));
         }
       }
     }
@@ -159,18 +237,157 @@
         node.readElement is PropertyAccessorElement) {
       var property = node.readElement as PropertyAccessorElement;
       if (property.variable == element) {
-        offsets.add(node.rightHandSide.offset);
+        references.add(MatchInfo(node.rightHandSide.offset,
+            node.rightHandSide.length, MatchKind.READ));
+      }
+    }
+  }
+
+  @override
+  visitCommentReference(CommentReference node) {
+    var expression = node.expression;
+    if (expression is Identifier) {
+      var element = expression.staticElement;
+      if (element is ConstructorElement) {
+        if (expression is PrefixedIdentifier) {
+          var offset = expression.prefix.end;
+          var length = expression.end - offset;
+          references.add(MatchInfo(offset, length, MatchKind.REFERENCE));
+          return;
+        } else {
+          var offset = expression.end;
+          references.add(MatchInfo(offset, 0, MatchKind.REFERENCE));
+          return;
+        }
+      }
+    } else if (expression is PropertyAccess) {
+      // Nothing to do?
+    } else {
+      throw UnimplementedError('Unhandled CommentReference expression type: '
+          '${expression.runtimeType}');
+    }
+  }
+
+  @override
+  visitConstructorDeclaration(ConstructorDeclaration node) {
+    var e = node.declaredElement;
+    if (e == element) {
+      if (e!.name.isEmpty) {
+        references.add(
+            MatchInfo(e.nameOffset + e.nameLength, 0, MatchKind.DECLARATION));
+      } else {
+        var offset = node.period!.offset;
+        var length = node.name!.end - offset;
+        references.add(MatchInfo(offset, length, MatchKind.DECLARATION));
+      }
+    }
+    super.visitConstructorDeclaration(node);
+  }
+
+  @override
+  void visitConstructorName(ConstructorName node) {
+    var e = node.staticElement?.declaration;
+    e = _getActualConstructorElement(e);
+    MatchKind kind;
+    int offset;
+    int length;
+    if (e == element) {
+      if (node.parent is ConstructorReference) {
+        kind = MatchKind.REFERENCE_BY_CONSTRUCTOR_TEAR_OFF;
+      } else if (node.parent is InstanceCreationExpression) {
+        kind = MatchKind.INVOCATION;
+      } else {
+        kind = MatchKind.REFERENCE;
+      }
+      if (node.name != null) {
+        offset = node.period!.offset;
+        length = node.name!.end - offset;
+      } else {
+        offset = node.type.end;
+        length = 0;
+      }
+      references.add(MatchInfo(offset, length, kind));
+    }
+    if (e!.enclosingElement == element) {
+      kind = MatchKind.REFERENCE;
+      offset = node.offset;
+      length = element.nameLength;
+      references.add(MatchInfo(offset, length, kind));
+    }
+  }
+
+  @override
+  void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
+    var constructorElement = node.constructorElement;
+    if (constructorElement != null && constructorElement == element) {
+      int offset;
+      int length;
+      var constructorSelector = node.arguments?.constructorSelector;
+      if (constructorSelector != null) {
+        offset = constructorSelector.period.offset;
+        length = constructorSelector.name.end - offset;
+      } else {
+        offset = node.name.end;
+        length = 0;
+      }
+      var kind = node.arguments == null
+          ? MatchKind.INVOCATION_BY_ENUM_CONSTANT_WITHOUT_ARGUMENTS
+          : MatchKind.INVOCATION;
+      references.add(MatchInfo(offset, length, kind));
+    }
+  }
+
+  @override
+  void visitRedirectingConstructorInvocation(
+      RedirectingConstructorInvocation node) {
+    var e = node.staticElement;
+    if (e == element) {
+      if (node.constructorName != null) {
+        int offset = node.period!.offset;
+        int length = node.constructorName!.end - offset;
+        references.add(MatchInfo(offset, length, MatchKind.INVOCATION));
+      } else {
+        int offset = node.thisKeyword.end;
+        references.add(MatchInfo(offset, 0, MatchKind.INVOCATION));
       }
     }
   }
 
   @override
   void visitSimpleIdentifier(SimpleIdentifier node) {
+    if (node.inDeclarationContext()) {
+      return;
+    }
     var e = node.staticElement;
     if (e == element) {
-      offsets.add(node.offset);
+      references.add(MatchInfo(node.offset, node.length, MatchKind.REFERENCE));
     } else if (e is PropertyAccessorElement && e.variable == element) {
-      offsets.add(node.offset);
+      bool inGetterContext = node.inGetterContext();
+      bool inSetterContext = node.inSetterContext();
+      MatchKind kind;
+      if (inGetterContext && inSetterContext) {
+        kind = MatchKind.READ_WRITE;
+      } else if (inGetterContext) {
+        kind = MatchKind.READ;
+      } else {
+        kind = MatchKind.WRITE;
+      }
+      references.add(MatchInfo(node.offset, node.length, kind));
+    }
+  }
+
+  @override
+  void visitSuperConstructorInvocation(SuperConstructorInvocation node) {
+    var e = node.staticElement;
+    if (e == element) {
+      if (node.constructorName != null) {
+        int offset = node.period!.offset;
+        int length = node.constructorName!.end - offset;
+        references.add(MatchInfo(offset, length, MatchKind.INVOCATION));
+      } else {
+        int offset = node.superKeyword.end;
+        references.add(MatchInfo(offset, 0, MatchKind.INVOCATION));
+      }
     }
   }
 }
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 f0b0c235..934b7bd 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
@@ -396,8 +396,8 @@
     var element = await _findElement(6, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(4, 11)]),
-      CiderSearchMatch(aPath, [CharacterLocation(1, 7)])
+      CiderSearchMatch(bPath, [CharacterLocation(4, 11)],
+          [CiderSearchInfo(CharacterLocation(4, 11), 1, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
   }
@@ -418,10 +418,10 @@
     var element = await _findElement(16, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(
-          aPath, [CharacterLocation(2, 7), CharacterLocation(5, 5)])
+      CiderSearchMatch(aPath, [CharacterLocation(5, 5)],
+          [CiderSearchInfo(CharacterLocation(5, 5), 3, MatchKind.WRITE)])
     ];
-    expect(result, unorderedEquals(expected));
+    expect(result, expected);
   }
 
   test_findReferences_function() async {
@@ -438,8 +438,8 @@
     var element = await _findElement(11, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(
-          aPath, [CharacterLocation(2, 3), CharacterLocation(5, 1)])
+      CiderSearchMatch(aPath, [CharacterLocation(2, 3)],
+          [CiderSearchInfo(CharacterLocation(2, 3), 3, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
   }
@@ -465,8 +465,8 @@
     var element = await _findElement(20, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(5, 15)]),
-      CiderSearchMatch(aPath, [CharacterLocation(2, 11)])
+      CiderSearchMatch(bPath, [CharacterLocation(5, 15)],
+          [CiderSearchInfo(CharacterLocation(5, 15), 3, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
   }
@@ -485,8 +485,8 @@
     var element = await _findElement(39, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(
-          aPath, [CharacterLocation(3, 9), CharacterLocation(4, 11)])
+      CiderSearchMatch(aPath, [CharacterLocation(4, 11)],
+          [CiderSearchInfo(CharacterLocation(4, 11), 3, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
   }
@@ -519,9 +519,10 @@
     var element = await _findElement(17, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(5, 5)]),
-      CiderSearchMatch(
-          aPath, [CharacterLocation(2, 8), CharacterLocation(7, 4)])
+      CiderSearchMatch(bPath, [CharacterLocation(5, 5)],
+          [CiderSearchInfo(CharacterLocation(5, 5), 4, MatchKind.REFERENCE)]),
+      CiderSearchMatch(aPath, [CharacterLocation(7, 4)],
+          [CiderSearchInfo(CharacterLocation(7, 4), 4, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
   }
@@ -547,8 +548,8 @@
     var element = await _findElement(21, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(5, 5)]),
-      CiderSearchMatch(aPath, [CharacterLocation(2, 12)])
+      CiderSearchMatch(bPath, [CharacterLocation(5, 5)],
+          [CiderSearchInfo(CharacterLocation(5, 5), 5, MatchKind.WRITE)])
     ];
     expect(result, unorderedEquals(expected));
   }
@@ -575,8 +576,8 @@
     var element = await _findElement(19, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(4, 13)]),
-      CiderSearchMatch(aPath, [CharacterLocation(3, 9)])
+      CiderSearchMatch(bPath, [CharacterLocation(4, 13)],
+          [CiderSearchInfo(CharacterLocation(4, 13), 3, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
   }
@@ -603,8 +604,8 @@
     var element = await _findElement(20, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(4, 3)]),
-      CiderSearchMatch(aPath, [CharacterLocation(3, 10)])
+      CiderSearchMatch(bPath, [CharacterLocation(4, 3)],
+          [CiderSearchInfo(CharacterLocation(4, 3), 3, MatchKind.WRITE)]),
     ];
     expect(result, unorderedEquals(expected));
   }
@@ -624,8 +625,8 @@
     var element = await _findElement(10, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(
-          aPath, [CharacterLocation(1, 11), CharacterLocation(4, 11)])
+      CiderSearchMatch(aPath, [CharacterLocation(4, 11)],
+          [CiderSearchInfo(CharacterLocation(4, 11), 1, MatchKind.READ)])
     ];
     expect(result, unorderedEquals(expected));
   }
@@ -644,14 +645,20 @@
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
       CiderSearchMatch(aPath, [
-        CharacterLocation(1, 11),
         CharacterLocation(2, 8),
         CharacterLocation(4, 12)
+      ], [
+        CiderSearchInfo(CharacterLocation(2, 8), 5, MatchKind.WRITE),
+        CiderSearchInfo(CharacterLocation(4, 12), 5, MatchKind.WRITE)
       ])
     ];
     expect(result.map((e) => e.path),
         unorderedEquals(expected.map((e) => e.path)));
-    expect(result.map((e) => e.startPositions),
+    // ignore: deprecated_member_use_from_same_package
+    expect(
+        // ignore: deprecated_member_use_from_same_package
+        result.map((e) => e.startPositions),
+        // ignore: deprecated_member_use_from_same_package
         unorderedEquals(expected.map((e) => e.startPositions)));
   }
 
@@ -672,8 +679,8 @@
     var element = await _findElement(8, aPath);
     var result = await fileResolver.findReferences2(element);
     var expected = <CiderSearchMatch>[
-      CiderSearchMatch(bPath, [CharacterLocation(3, 8)]),
-      CiderSearchMatch(aPath, [CharacterLocation(1, 9)])
+      CiderSearchMatch(bPath, [CharacterLocation(3, 8)],
+          [CiderSearchInfo(CharacterLocation(3, 8), 4, MatchKind.REFERENCE)])
     ];
     expect(result, unorderedEquals(expected));
   }