Index, search, rename for pattern fields.

Change-Id: Iaeae578d18c139850664f30fc5bbc92ad95132ac
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/283127
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/test/edit/refactoring_test.dart b/pkg/analysis_server/test/edit/refactoring_test.dart
index b78bc5e..4d11be4 100644
--- a/pkg/analysis_server/test/edit/refactoring_test.dart
+++ b/pkg/analysis_server/test/edit/refactoring_test.dart
@@ -1605,6 +1605,56 @@
     );
   }
 
+  Future<void> test_class_getter_in_objectPattern() {
+    addTestFile('''
+void f(Object? x) {
+  if (x case A(test: 0)) {}
+  if (x case A(: var test)) {}
+}
+
+class A {
+  int get test => 0;
+}
+''');
+    return assertSuccessfulRefactoring(() {
+      return sendRenameRequest('test =>', 'newName');
+    }, '''
+void f(Object? x) {
+  if (x case A(newName: 0)) {}
+  if (x case A(newName: var test)) {}
+}
+
+class A {
+  int get newName => 0;
+}
+''');
+  }
+
+  Future<void> test_class_method_in_objectPattern() {
+    addTestFile('''
+void f(Object? x) {
+  if (x case A(test: _)) {}
+  if (x case A(: var test)) {}
+}
+
+class A {
+  void test() {}
+}
+''');
+    return assertSuccessfulRefactoring(() {
+      return sendRenameRequest('test() {}', 'newName');
+    }, '''
+void f(Object? x) {
+  if (x case A(newName: _)) {}
+  if (x case A(newName: var test)) {}
+}
+
+class A {
+  void newName() {}
+}
+''');
+  }
+
   Future<void> test_class_options_fatalError() {
     addTestFile('''
 class Test {}
diff --git a/pkg/analysis_server/test/search/element_references_test.dart b/pkg/analysis_server/test/search/element_references_test.dart
index de8f23e..5355f79 100644
--- a/pkg/analysis_server/test/search/element_references_test.dart
+++ b/pkg/analysis_server/test/search/element_references_test.dart
@@ -241,6 +241,24 @@
     assertHasResult(SearchResultKind.READ, 'fff); // in m()');
   }
 
+  Future<void> test_class_getter_in_objectPattern() async {
+    addTestFile('''
+void f(Object? x) {
+  if (x case A(foo: 0)) {}
+  if (x case A(: var foo)) {}
+}
+
+class A {
+  int get foo => 0;
+}
+''');
+    await findElementReferences('foo =>', false);
+    expect(searchElement!.kind, ElementKind.FIELD);
+    expect(results, hasLength(2));
+    assertHasResult(SearchResultKind.READ, 'foo: 0');
+    assertHasResult(SearchResultKind.READ, ': var foo');
+  }
+
   Future<void> test_class_method() async {
     addTestFile('''
 class A {
diff --git a/pkg/analysis_server/test/services/refactoring/legacy/rename_class_member_test.dart b/pkg/analysis_server/test/services/refactoring/legacy/rename_class_member_test.dart
index c464865..f1666db 100644
--- a/pkg/analysis_server/test/services/refactoring/legacy/rename_class_member_test.dart
+++ b/pkg/analysis_server/test/services/refactoring/legacy/rename_class_member_test.dart
@@ -644,6 +644,66 @@
 ''');
   }
 
+  Future<void> test_createChange_getter_in_objectPattern() async {
+    await indexTestUnit('''
+void f(Object? x) {
+  if (x case A(test: 0)) {}
+  if (x case A(: var test)) {}
+}
+
+class A {
+  int get test => 0;
+}
+''');
+    // configure refactoring
+    createRenameRefactoringAtString('test =>');
+    expect(refactoring.refactoringName, 'Rename Field');
+    expect(refactoring.elementKindName, 'field');
+    expect(refactoring.oldName, 'test');
+    refactoring.newName = 'newName';
+    // validate change
+    return assertSuccessfulRefactoring('''
+void f(Object? x) {
+  if (x case A(newName: 0)) {}
+  if (x case A(newName: var test)) {}
+}
+
+class A {
+  int get newName => 0;
+}
+''');
+  }
+
+  Future<void> test_createChange_method_in_objectPattern() async {
+    await indexTestUnit('''
+void f(Object? x) {
+  if (x case A(test: _)) {}
+  if (x case A(: var test)) {}
+}
+
+class A {
+  void test() {}
+}
+''');
+    // configure refactoring
+    createRenameRefactoringAtString('test() {}');
+    expect(refactoring.refactoringName, 'Rename Method');
+    expect(refactoring.elementKindName, 'method');
+    expect(refactoring.oldName, 'test');
+    refactoring.newName = 'newName';
+    // validate change
+    return assertSuccessfulRefactoring('''
+void f(Object? x) {
+  if (x case A(newName: _)) {}
+  if (x case A(newName: var test)) {}
+}
+
+class A {
+  void newName() {}
+}
+''');
+  }
+
   Future<void> test_createChange_MethodElement() async {
     await indexTestUnit('''
 /// [A.test]
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
index bff4eb5..b5538b9 100644
--- a/pkg/analyzer/lib/src/dart/analysis/index.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -806,6 +806,26 @@
   }
 
   @override
+  visitPatternField(PatternField node) {
+    final nameNode = node.name;
+    if (nameNode != null) {
+      final nameToken = nameNode.name;
+      final int offset;
+      final int length;
+      if (nameToken != null) {
+        offset = nameToken.offset;
+        length = nameToken.length;
+      } else {
+        offset = nameNode.offset;
+        length = 0;
+      }
+      recordRelationOffset(node.element, IndexRelationKind.IS_REFERENCED_BY,
+          offset, length, true);
+    }
+    return super.visitPatternField(node);
+  }
+
+  @override
   void visitPostfixExpression(PostfixExpression node) {
     recordOperatorReference(node.operator, node.staticElement);
     super.visitPostfixExpression(node);
diff --git a/pkg/analyzer/lib/src/dart/ast/element_locator.dart b/pkg/analyzer/lib/src/dart/ast/element_locator.dart
index 525f284..0b4f29d 100644
--- a/pkg/analyzer/lib/src/dart/ast/element_locator.dart
+++ b/pkg/analyzer/lib/src/dart/ast/element_locator.dart
@@ -211,8 +211,9 @@
     final parent = node.parent;
     if (parent is PatternField) {
       return parent.element;
+    } else {
+      return null;
     }
-    return super.visitPatternFieldName(node);
   }
 
   @override
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index eaf1d0a..fb09c58 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -710,6 +710,42 @@
 ''');
   }
 
+  test_isReferencedBy_class_getter_in_objectPattern() async {
+    await _indexTestUnit('''
+void f(Object? x) {
+  if (x case A(foo: 0)) {}
+  if (x case A(: var foo)) {}
+}
+
+class A {
+  int get foo => 0;
+}
+''');
+    final element = findElement.getter('foo');
+    assertElementIndexText(element, r'''
+35 2:16 |foo| IS_REFERENCED_BY qualified
+62 3:16 || IS_REFERENCED_BY qualified
+''');
+  }
+
+  test_isReferencedBy_class_method_in_objectPattern() async {
+    await _indexTestUnit('''
+void f(Object? x) {
+  if (x case A(foo: _)) {}
+  if (x case A(: var foo)) {}
+}
+
+class A {
+  void foo() {}
+}
+''');
+    final element = findElement.method('foo');
+    assertElementIndexText(element, r'''
+35 2:16 |foo| IS_REFERENCED_BY qualified
+62 3:16 || IS_REFERENCED_BY qualified
+''');
+  }
+
   test_isReferencedBy_ClassElement() async {
     await _indexTestUnit('''
 class A {
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index 3ea2a29..a0be39c 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -577,6 +577,46 @@
     ]);
   }
 
+  test_searchReferences_class_getter_in_objectPattern() async {
+    await resolveTestCode('''
+void f(Object? x) {
+  if (x case A(foo: 0)) {}
+  if (x case A(: var foo)) {}
+}
+
+class A {
+  int get foo => 0;
+}
+''');
+    var element = findElement.getter('foo');
+    var f = findElement.function('f');
+    var expected = [
+      _expectIdQ(f, SearchResultKind.REFERENCE, 'foo: 0', length: 3),
+      _expectIdQ(f, SearchResultKind.REFERENCE, ': var foo', length: 0),
+    ];
+    await _verifyReferences(element, expected);
+  }
+
+  test_searchReferences_class_method_in_objectPattern() async {
+    await resolveTestCode('''
+void f(Object? x) {
+  if (x case A(foo: _)) {}
+  if (x case A(: var foo)) {}
+}
+
+class A {
+  void foo() {}
+}
+''');
+    var element = findElement.method('foo');
+    var f = findElement.function('f');
+    var expected = [
+      _expectIdQ(f, SearchResultKind.REFERENCE, 'foo: _', length: 3),
+      _expectIdQ(f, SearchResultKind.REFERENCE, ': var foo', length: 0),
+    ];
+    await _verifyReferences(element, expected);
+  }
+
   test_searchReferences_ClassElement_definedInSdk_declarationSite() async {
     await resolveTestCode('''
 import 'dart:math';
diff --git a/pkg/analyzer/test/src/dart/ast/element_locator_test.dart b/pkg/analyzer/test/src/dart/ast/element_locator_test.dart
index 9c1920f..8620219 100644
--- a/pkg/analyzer/test/src/dart/ast/element_locator_test.dart
+++ b/pkg/analyzer/test/src/dart/ast/element_locator_test.dart
@@ -346,6 +346,17 @@
     expect(element, isLibraryElement);
   }
 
+  test_locate_PatternField() async {
+    await resolveTestCode(r'''
+void f(Object? x) {
+  if (x case int(isEven: true)) {}
+}
+''');
+    var node = findNode.patternField('isEven:');
+    var element = ElementLocator.locate(node);
+    expect(element, isPropertyAccessorElement);
+  }
+
   test_locate_PostfixExpression() async {
     await resolveTestCode('int addOne(int x) => x++;');
     var node = findNode.postfix('x++');