Allow authors to specify that a member is static

This information isn't currently being used, but the intention is to not
apply a transform for a static element if the reference to the element
isn't qualified by the name of the container (because outside the
container all references to a static member must be qualifed).

Change-Id: I9e316c32287e6cf3dcdfd911296bc3948f1749e2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/225460
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Brian Wilkerson <brianwilkerson@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
index 4b9619d..5f96489 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_descriptor.dart
@@ -7,7 +7,7 @@
 import 'package:analyzer/dart/element/element.dart' show ClassElement;
 import 'package:analyzer/dart/element/type.dart';
 
-/// The path to an element.
+/// A description of an element.
 class ElementDescriptor {
   /// The URIs of the library in which the element is defined.
   final List<Uri> libraryUris;
@@ -15,6 +15,14 @@
   /// The kind of element that was changed.
   final ElementKind kind;
 
+  /// A flag indicating whether the element is a static member of a container
+  /// such as a class, enum, mixin, or extension.
+  ///
+  /// The flag should be `false` for top-level declarations. The implication is
+  /// that the flag will only be true if the list of [components] has more than
+  /// one element.
+  final bool isStatic;
+
   /// The components that uniquely identify the element within its library. The
   /// components are ordered from the most local to the most global.
   final List<String> components;
@@ -26,6 +34,7 @@
   ElementDescriptor(
       {required this.libraryUris,
       required this.kind,
+      required this.isStatic,
       required this.components});
 
   /// Return `true` if the described element is a constructor.
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
index 42aeba2..7fc4864 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_error_code.dart
@@ -156,6 +156,14 @@
   /**
    * No parameters.
    */
+  static const TransformSetErrorCode unsupportedStatic = TransformSetErrorCode(
+      'unsupported_static',
+      "The key 'static' is only supported for elements in a class, enum, "
+          "extension, or mixin.");
+
+  /**
+   * No parameters.
+   */
   static const TransformSetErrorCode unsupportedUriChange = TransformSetErrorCode(
       'unsupported_uri_change',
       "The set of URIs for the replacement element must match the transformed "
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
index b65d750..29913b3 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/transform_set_parser.dart
@@ -71,6 +71,7 @@
   static const String _oneOfKey = 'oneOf';
   static const String _requiredIfKey = 'requiredIf';
   static const String _setterKey = 'setter';
+  static const String _staticKey = 'static';
   static const String _styleKey = 'style';
   static const String _titleKey = 'title';
   static const String _transformsKey = 'transforms';
@@ -662,6 +663,8 @@
         return null;
       }
       var components = [elementName];
+      var isStatic = false;
+      var staticNode = node.valueAt(_staticKey);
       if (_containerKeyMap.containsKey(elementKey)) {
         var validContainerKeys = _containerKeyMap[elementKey]!;
         var containerKey =
@@ -684,6 +687,20 @@
         } else {
           components.add(containerName);
         }
+        if (staticNode != null) {
+          var staticValue = _translateBool(
+              staticNode, ErrorContext(key: _staticKey, parentNode: node));
+          if (staticValue != null) {
+            if (components.length == 1) {
+              _reportError(TransformSetErrorCode.unsupportedStatic,
+                  node.getKey(_staticKey)!);
+            }
+            isStatic = staticValue;
+          }
+        }
+      } else if (staticNode != null) {
+        _reportError(
+            TransformSetErrorCode.unsupportedStatic, node.getKey(_staticKey)!);
       }
       if (uris == null) {
         // The error has already been reported.
@@ -698,6 +715,7 @@
       return ElementDescriptor(
           libraryUris: uris,
           kind: ElementKindUtilities.fromName(elementKey)!,
+          isStatic: isStatic,
           components: components);
     } else if (node == null) {
       return _reportMissingKey(context);
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
index fab212b..dff9c05 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/add_type_parameter_test.dart
@@ -477,13 +477,17 @@
   /// Return the kind of element whose parameters are being modified.
   String get _kind;
 
-  Transform _add(int index, {List<String>? components, String? extendedType}) =>
+  Transform _add(int index,
+          {List<String>? components,
+          String? extendedType,
+          bool isStatic = false}) =>
       Transform(
           title: 'title',
           date: DateTime.now(),
           element: ElementDescriptor(
               libraryUris: [Uri.parse(importUri)],
               kind: ElementKindUtilities.fromName(_kind)!,
+              isStatic: isStatic,
               components: components ?? ['m', 'C']),
           bulkApply: false,
           changesSelector: UnconditionalChangesSelector([
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
index 375c983..6ec3458 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/test_all.dart
@@ -23,6 +23,7 @@
 import 'unexpected_token_test.dart' as unexpected_token;
 import 'unknown_accessor_test.dart' as unknown_accessor;
 import 'unsupported_key_test.dart' as unsupported_key;
+import 'unsupported_static_test.dart' as unsupported_static;
 import 'unsupported_uri_change_test.dart' as unsupported_uri_change;
 import 'unsupported_version_test.dart' as unsupported_version;
 import 'wrong_token_test.dart' as wrong_token;
@@ -49,6 +50,7 @@
     unexpected_token.main();
     unknown_accessor.main();
     unsupported_key.main();
+    unsupported_static.main();
     unsupported_uri_change.main();
     unsupported_version.main();
     wrong_token.main();
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unsupported_static_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unsupported_static_test.dart
new file mode 100644
index 0000000..2ef1446
--- /dev/null
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/diagnostics/unsupported_static_test.dart
@@ -0,0 +1,64 @@
+// 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:analysis_server/src/services/correction/fix/data_driven/transform_set_error_code.dart';
+import 'package:test_reflective_loader/test_reflective_loader.dart';
+
+import '../transform_set_parser_test_support.dart';
+
+void main() {
+  defineReflectiveSuite(() {
+    defineReflectiveTests(UnsupportedStaticTest);
+  });
+}
+
+@reflectiveTest
+class UnsupportedStaticTest extends AbstractTransformSetParserTest {
+  void test_class() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2021-11-22
+  element:
+    uris: ['test.dart']
+    class: 'C'
+    static: true
+  changes: []
+''', [
+      error(TransformSetErrorCode.unsupportedStatic, 108, 6),
+    ]);
+  }
+
+  void test_getter_inClass() {
+    assertNoErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2021-11-22
+  element:
+    uris: ['test.dart']
+    getter: 'm'
+    inClass: 'C'
+    static: true
+  changes: []
+''');
+  }
+
+  void test_getter_topLevel() {
+    assertErrors('''
+version: 1
+transforms:
+- title: ''
+  date: 2021-11-22
+  element:
+    uris: ['test.dart']
+    getter: 'g'
+    static: true
+  changes: []
+''', [
+      error(TransformSetErrorCode.unsupportedStatic, 109, 6),
+    ]);
+  }
+}
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
index 535320f..8fcb8d5 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/modify_parameters_test.dart
@@ -1006,13 +1006,15 @@
   String get _kind;
 
   Transform _modify(List<String> originalComponents,
-          List<ParameterModification> modifications, {String? newName}) =>
+          List<ParameterModification> modifications,
+          {String? newName, bool isStatic = false}) =>
       Transform(
           title: 'title',
           date: DateTime.now(),
           element: ElementDescriptor(
               libraryUris: [Uri.parse(importUri)],
               kind: ElementKindUtilities.fromName(_kind)!,
+              isStatic: isStatic,
               components: originalComponents),
           bulkApply: false,
           changesSelector: UnconditionalChangesSelector([
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_parameter_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_parameter_test.dart
index 59d5f50..eb0bafa 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_parameter_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_parameter_test.dart
@@ -328,13 +328,15 @@
   /// Return the kind of element containing the parameter being renamed.
   String get _kind;
 
-  Transform _rename(List<String> components, String oldName, String newName) =>
+  Transform _rename(List<String> components, String oldName, String newName,
+          {bool isStatic = false}) =>
       Transform(
           title: 'title',
           date: DateTime.now(),
           element: ElementDescriptor(
               libraryUris: [Uri.parse(importUri)],
               kind: ElementKindUtilities.fromName(_kind)!,
+              isStatic: isStatic,
               components: components),
           bulkApply: false,
           changesSelector: UnconditionalChangesSelector([
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_test.dart
index cf1aeb9..d39a127 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/rename_test.dart
@@ -1533,15 +1533,18 @@
   /// Return the kind of element being renamed.
   String get _kind;
 
-  Transform _rename(List<String> components, String newName) => Transform(
-      title: 'title',
-      date: DateTime.now(),
-      element: ElementDescriptor(
-          libraryUris: [Uri.parse(importUri)],
-          kind: ElementKindUtilities.fromName(_kind)!,
-          components: components),
-      bulkApply: false,
-      changesSelector: UnconditionalChangesSelector([
-        Rename(newName: newName),
-      ]));
+  Transform _rename(List<String> components, String newName,
+          {bool isStatic = false}) =>
+      Transform(
+          title: 'title',
+          date: DateTime.now(),
+          element: ElementDescriptor(
+              libraryUris: [Uri.parse(importUri)],
+              kind: ElementKindUtilities.fromName(_kind)!,
+              isStatic: isStatic,
+              components: components),
+          bulkApply: false,
+          changesSelector: UnconditionalChangesSelector([
+            Rename(newName: newName),
+          ]));
 }
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/replaced_by_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/replaced_by_test.dart
index 03d89fe..a7b70a4 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/replaced_by_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/replaced_by_test.dart
@@ -838,12 +838,19 @@
   }
 
   Transform _replacedBy(ElementKind oldKind, List<String> oldComponents,
-      ElementKind newKind, List<String> newComponents) {
+      ElementKind newKind, List<String> newComponents,
+      {bool isStatic = false}) {
     var uris = [Uri.parse(importUri)];
     var oldElement = ElementDescriptor(
-        libraryUris: uris, kind: oldKind, components: oldComponents);
+        libraryUris: uris,
+        kind: oldKind,
+        isStatic: isStatic,
+        components: oldComponents);
     var newElement2 = ElementDescriptor(
-        libraryUris: uris, kind: newKind, components: newComponents);
+        libraryUris: uris,
+        kind: newKind,
+        isStatic: isStatic,
+        components: newComponents);
     return Transform(
         title: 'title',
         date: DateTime.now(),
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_override_set_parser_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_override_set_parser_test.dart
index af7b127..9d4c388 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_override_set_parser_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_override_set_parser_test.dart
@@ -15,7 +15,7 @@
 
 void main() {
   defineReflectiveSuite(() {
-    defineReflectiveTests(TransformSetParserTest);
+    defineReflectiveTests(TransformOverrideSetParserTest);
   });
 }
 
@@ -64,7 +64,8 @@
 }
 
 @reflectiveTest
-class TransformSetParserTest extends AbstractTransformOverrideSetParserTest {
+class TransformOverrideSetParserTest
+    extends AbstractTransformOverrideSetParserTest {
   void test_emptyFile() {
     assertErrors('''
 ''', [error(TransformSetErrorCode.invalidValue, 0, 0)]);
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
index 51421b4..95055f4 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/transform_set_parser_test.dart
@@ -525,6 +525,32 @@
     var transform = transforms[0];
     expect(transform.title, 'Rename m');
     expect(_changes(transform), isEmpty);
+    var element = transform.element;
+    expect(element.components, ['m', 'A']);
+    expect(element.isStatic, isFalse);
+  }
+
+  void test_element_method_inExtension_static() {
+    assertNoErrors('''
+version: 1
+transforms:
+- title: 'Rename m'
+  date: 2020-09-02
+  element:
+    uris: ['test.dart']
+    method: 'm'
+    inExtension: 'E'
+    static: true
+  changes: []
+''');
+    var transforms = _transforms('m');
+    expect(transforms, hasLength(1));
+    var transform = transforms[0];
+    expect(transform.title, 'Rename m');
+    expect(_changes(transform), isEmpty);
+    var element = transform.element;
+    expect(element.components, ['m', 'E']);
+    expect(element.isStatic, isTrue);
   }
 
   void test_element_variable() {