[analyzer] Dot shorthands: Update indexing.

Adds implementation for dot shorthand invocations, property accesses and constructors in indexing and added search tests.

Unit tests passing for index and search.

Bug: https://github.com/dart-lang/sdk/issues/59835
Change-Id: I2ee3ddbabb7f8ee0ead6538906a9a55f54bf20a2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/430563
Commit-Queue: Kallen Tu <kallentu@google.com>
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Chloe Stefantsova <cstefantsova@google.com>
diff --git a/pkg/analyzer/lib/src/dart/analysis/index.dart b/pkg/analyzer/lib/src/dart/analysis/index.dart
index 7a22d00..dd085c2 100644
--- a/pkg/analyzer/lib/src/dart/analysis/index.dart
+++ b/pkg/analyzer/lib/src/dart/analysis/index.dart
@@ -861,6 +861,41 @@
   }
 
   @override
+  void visitDotShorthandConstructorInvocation(
+    DotShorthandConstructorInvocation node,
+  ) {
+    var element = _getActualConstructorElement(node.element?.baseElement);
+    recordRelation(
+      element,
+      IndexRelationKind.IS_INVOKED_BY,
+      node.constructorName,
+      true,
+    );
+  }
+
+  @override
+  void visitDotShorthandInvocation(DotShorthandInvocation node) {
+    var name = node.memberName;
+    var element = name.element;
+    recordRelation(element, IndexRelationKind.IS_INVOKED_BY, name, true);
+    node.typeArguments?.accept(this);
+    node.argumentList.accept(this);
+  }
+
+  @override
+  void visitDotShorthandPropertyAccess(DotShorthandPropertyAccess node) {
+    IndexRelationKind kind;
+    var element = node.propertyName.element;
+    if (element is ConstructorElementMixin2) {
+      element = _getActualConstructorElement(element);
+      kind = IndexRelationKind.IS_REFERENCED_BY_CONSTRUCTOR_TEAR_OFF;
+    } else {
+      kind = IndexRelationKind.IS_REFERENCED_BY;
+    }
+    recordRelation(element, kind, node.propertyName, true);
+  }
+
+  @override
   void visitEnumConstantDeclaration(EnumConstantDeclaration node) {
     var constructorElement = node.constructorElement2;
     if (constructorElement != null) {
diff --git a/pkg/analyzer/test/src/dart/analysis/index_test.dart b/pkg/analyzer/test/src/dart/analysis/index_test.dart
index 29d9081..b882549 100644
--- a/pkg/analyzer/test/src/dart/analysis/index_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/index_test.dart
@@ -1280,6 +1280,21 @@
     // No additional validation, but it should not fail with stack overflow.
   }
 
+  test_isReferencedBy_ConstructorElement_dotShorthand() async {
+    await _indexTestUnit('''
+class A {}
+void f() {
+  A a = .new(); // 1
+  A tearOff = .new; // 2, is also a compile-time error
+}
+''');
+    var element = findElement2.unnamedConstructor('A');
+    assertElementIndexText(element, r'''
+31 3:10 |new| IS_INVOKED_BY qualified
+58 4:16 |new| IS_REFERENCED_BY_CONSTRUCTOR_TEAR_OFF qualified
+''');
+  }
+
   test_isReferencedBy_ConstructorElement_enum_named() async {
     await _indexTestUnit('''
 /// [new E.foo] 1
@@ -1706,6 +1721,21 @@
 ''');
   }
 
+  test_isReferencedBy_FieldElement_dotShorthand() async {
+    await _indexTestUnit('''
+class A {
+  static A field = A();
+}
+void f() {
+  A a = .field; // 1
+}
+''');
+    var element = findElement2.field('field').getter2!;
+    assertElementIndexText(element, r'''
+56 5:10 |field| IS_REFERENCED_BY qualified
+''');
+  }
+
   test_isReferencedBy_FieldElement_enum() async {
     await _indexTestUnit('''
 enum E {
@@ -1953,6 +1983,21 @@
 ''');
   }
 
+  test_isReferencedBy_MethodElement_dotShorthand() async {
+    await _indexTestUnit('''
+class A {
+  static A method() => A();
+}
+void f() {
+  A a = .method(); // 1
+}
+''');
+    var element = findElement2.method('method');
+    assertElementIndexText(element, r'''
+60 5:10 |method| IS_INVOKED_BY qualified
+''');
+  }
+
   test_isReferencedBy_MethodElement_enum() async {
     await _indexTestUnit('''
 enum E {
diff --git a/pkg/analyzer/test/src/dart/analysis/search_test.dart b/pkg/analyzer/test/src/dart/analysis/search_test.dart
index 80a529c..98e5ee5 100644
--- a/pkg/analyzer/test/src/dart/analysis/search_test.dart
+++ b/pkg/analyzer/test/src/dart/analysis/search_test.dart
@@ -1304,6 +1304,22 @@
 ''');
   }
 
+  test_searchReferences_ConstructorElement_dotShorthand() async {
+    await resolveTestCode('''
+class A {}
+void main() {
+  A a = .new(); // 1
+  A tearOff = .new; // 2, is also a compile-time error
+}
+''');
+    var element = findElement2.unnamedConstructor('A');
+    await assertElementReferencesText(element, r'''
+<testLibraryFragment>::@function::main
+  34 3:10 |new| INVOCATION qualified
+  61 4:16 |new| REFERENCE_BY_CONSTRUCTOR_TEAR_OFF qualified
+''');
+  }
+
   test_searchReferences_ConstructorElement_enum_named() async {
     await resolveTestCode('''
 /// [new E.named] 1
@@ -1496,6 +1512,22 @@
 ''');
   }
 
+  test_searchReferences_FieldElement_dotShorthand() async {
+    await resolveTestCode('''
+class A {
+  static A field = A();
+}
+void main() {
+  A a = .field; // 1
+}
+''');
+    var element = findElement2.field('field');
+    await assertElementReferencesText(element, r'''
+<testLibraryFragment>::@function::main
+  59 5:10 |field| READ qualified
+''');
+  }
+
   test_searchReferences_FieldElement_enum() async {
     await resolveTestCode('''
 enum E {
@@ -1938,6 +1970,24 @@
 ''');
   }
 
+  test_searchReferences_MethodElement_dotShorthand() async {
+    await resolveTestCode('''
+class A {
+  static A method() => A();
+}
+void main() {
+  A a = .method(); // 1
+  A aa = .method; // 2, is also a compile-time error
+}
+''');
+    var element = findElement2.method('method');
+    await assertElementReferencesText(element, r'''
+<testLibraryFragment>::@function::main
+  63 5:10 |method| INVOCATION qualified
+  88 6:11 |method| REFERENCE qualified
+''');
+  }
+
   test_searchReferences_MethodElement_enum() async {
     await resolveTestCode('''
 enum E {