Fix data driven fix bug when the element in question is not resolved.

Fixes https://github.com/Dart-Code/Dart-Code/issues/4757.

Change-Id: Ifd160dbafa468db6a703209a6ee6ea1566da5223
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/328742
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Keerti Parthasarathy <keertip@google.com>
diff --git a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_matcher.dart b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_matcher.dart
index 6f76d7d..a40fa79 100644
--- a/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_matcher.dart
+++ b/pkg/analysis_server/lib/src/services/correction/fix/data_driven/element_matcher.dart
@@ -4,11 +4,11 @@
 
 import 'package:analysis_server/src/services/correction/fix/data_driven/element_descriptor.dart';
 import 'package:analysis_server/src/services/correction/fix/data_driven/element_kind.dart';
-import 'package:analyzer/dart/ast/ast.dart';
 import 'package:analyzer/dart/ast/token.dart';
 import 'package:analyzer/dart/element/element.dart'
     show ExtensionElement, InterfaceElement, PrefixElement;
 import 'package:analyzer/dart/element/type.dart';
+import 'package:analyzer/src/dart/ast/ast.dart';
 
 /// An object that can be used to determine whether an element is appropriate
 /// for a given reference.
@@ -26,13 +26,19 @@
   /// kinds.
   final List<ElementKind> validKinds;
 
+  /// The AST node to be matched with. The node is provided in cases where the
+  /// element in question cannot be resolved and relevant information cannot be
+  /// extracted as components.
+  final AstNode? node;
+
   /// Initialize a newly created matcher representing a reference to an element
   /// whose name matches the given [components] and element [kinds] in a library
   /// that imports the [importedUris].
   ElementMatcher(
       {required this.importedUris,
       required this.components,
-      required List<ElementKind> kinds})
+      required List<ElementKind> kinds,
+      this.node})
       : assert(components.isNotEmpty),
         validKinds = kinds;
 
@@ -67,12 +73,30 @@
       } else {
         // The node has fewer components, which can happen, for example, when we
         // can't figure out the class that used to define a field. We treat the
-        // missing components as wildcards and match the rest.
+        // missing components as wildcards and match the rest. If node is
+        // available, we further match against it.
         for (var i = 0; i < nodeComponentCount; i++) {
           if (elementComponents[i] != components[i]) {
             return false;
           }
         }
+        if (node != null) {
+          var parent = node?.parent;
+          while (parent != null && parent.parent is! CompilationUnit) {
+            parent = parent.parent;
+          }
+          var element = (parent as CompilationUnitMember).declaredElement;
+          if (element is! InterfaceElement) {
+            return false;
+          }
+          var types = element.allSupertypes.map((e) => e.element.name);
+          for (var t in types) {
+            if (elementComponents.contains(t)) {
+              return true;
+            }
+          }
+          return false;
+        }
       }
     } else {
       // The node has more components than the element, which can happen when a
@@ -189,9 +213,14 @@
   }
 
   void _addMatcher(
-      {required List<String> components, required List<ElementKind> kinds}) {
+      {required List<String> components,
+      required List<ElementKind> kinds,
+      AstNode? node}) {
     matchers.add(ElementMatcher(
-        importedUris: importedUris, components: components, kinds: kinds));
+        importedUris: importedUris,
+        components: components,
+        kinds: kinds,
+        node: node));
   }
 
   /// Build a matcher for the element being invoked.
@@ -494,7 +523,13 @@
       _buildFromPropertyAccess(parent);
     } else {
       // TODO(brianwilkerson) See whether the list of kinds can be specified.
-      _addMatcher(components: [node.name], kinds: []);
+      // If we cannot resolve the element. add the parent/target information,
+      // where it should have been declared.
+      if (node.staticType is InvalidType) {
+        _addMatcher(components: [node.name], kinds: [], node: node);
+      } else {
+        _addMatcher(components: [node.name], kinds: []);
+      }
     }
   }
 
diff --git a/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart b/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
index 8b9afd2..e0c6958 100644
--- a/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
+++ b/pkg/analysis_server/test/src/services/correction/fix/data_driven/flutter_use_case_test.dart
@@ -1876,6 +1876,315 @@
   }
 
   Future<void>
+      test_material_ThemeData_colorSchemeBackground_deprecated() async {
+    setPackageContent('''
+
+class ThemeData {
+
+  @deprecated
+  final Color  backgroundColor;
+  final ColorScheme colorScheme;
+  ThemeData(this.backgroundColor): colorScheme = ColorScheme(backgroundColor){}
+}
+
+class Color {
+  Color(int value) {}
+}
+
+class Colors {
+  Colors._();
+
+  static Color black = Color(0xFF000000);
+  static Color white = Color(0xFFFFFFFF);
+}
+
+class ColorScheme {
+    final Color background;
+    ColorScheme(this.background);
+}
+''');
+    addPackageDataFile('''
+version: 1
+transforms:
+  - title:  "Migrate to 'ColorScheme.background'"
+    date: 2020-09-24
+    element:
+      uris: ['$importUri']
+      field: 'backgroundColor'
+      inClass: 'ThemeData'
+    changes:
+      - kind: 'rename'
+        newName: 'colorScheme.background'
+''');
+    await resolveTestCode('''
+import '$importUri';
+
+void f() {
+  var themeData = ThemeData(Colors.black);
+  var color = themeData.backgroundColor;
+  print(color);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f() {
+  var themeData = ThemeData(Colors.black);
+  var color = themeData.colorScheme.background;
+  print(color);
+}
+''');
+  }
+
+  Future<void>
+      test_material_ThemeData_colorSchemeBackground_deprecated_noFix() async {
+    setPackageContent('''
+
+class ThemeData {
+
+  @deprecated
+  final Color  backgroundColor;
+  final ColorScheme colorScheme;
+  ThemeData(this.backgroundColor): colorScheme = ColorScheme(backgroundColor){}
+}
+
+class Color {
+  Color(int value) {}
+}
+
+class Colors {
+  Colors._();
+
+  static Color black = Color(0xFF000000);
+  static Color white = Color(0xFFFFFFFF);
+}
+
+class ColorScheme {
+    final Color background;
+    ColorScheme(this.background);
+}
+
+class ElevatedButton {
+   Color? color;
+
+  ElevatedButton(this.color);
+
+  static  ElevatedButton styleFrom({Color? backgroundColor}) {
+    return ElevatedButton(backgroundColor);
+  }
+}
+''');
+    addPackageDataFile('''
+version: 1
+transforms:
+  - title:  "Migrate to 'ColorScheme.background'"
+    date: 2020-09-24
+    element:
+      uris: ['$importUri']
+      field: 'backgroundColor'
+      inClass: 'ThemeData'
+    changes:
+      - kind: 'rename'
+        newName: 'colorScheme.background'
+''');
+    await resolveTestCode('''
+import '$importUri';
+
+void f() {
+  var a = ElevatedButton.styleFrom(backgroundColor: backgroundColor);
+  print(a);
+}
+''');
+    await assertNoFix();
+  }
+
+  Future<void>
+      test_material_ThemeData_colorSchemeBackground_deprecated_noFix2() async {
+    setPackageContent('''
+
+class ThemeData {
+
+  @deprecated
+  final Color  backgroundColor;
+  final ColorScheme colorScheme;
+  ThemeData(this.backgroundColor): colorScheme = ColorScheme(backgroundColor){}
+}
+
+class Color {
+  Color(int value) {}
+}
+
+class Colors {
+  Colors._();
+
+  static Color black = Color(0xFF000000);
+  static Color white = Color(0xFFFFFFFF);
+}
+
+class ColorScheme {
+    final Color background;
+    ColorScheme(this.background);
+}
+
+class ElevatedButton {
+   Color? color;
+
+  ElevatedButton(this.color);
+
+  static  ElevatedButton styleFrom({Color? backgroundColor}) {
+    return ElevatedButton(backgroundColor);
+  }
+}
+''');
+    addPackageDataFile('''
+version: 1
+transforms:
+  - title:  "Migrate to 'ColorScheme.background'"
+    date: 2020-09-24
+    element:
+      uris: ['$importUri']
+      field: 'backgroundColor'
+      inClass: 'ThemeData'
+    changes:
+      - kind: 'rename'
+        newName: 'colorScheme.background'
+''');
+    await resolveTestCode('''
+import '$importUri';
+
+class E {
+  void m() {
+    var a = ElevatedButton.styleFrom(backgroundColor: backgroundColor);
+    print(a);
+  }
+}
+''');
+    await assertNoFix();
+  }
+
+  Future<void> test_material_ThemeData_colorSchemeBackground_removed() async {
+    setPackageContent('''
+
+class ThemeData {
+
+  final ColorScheme colorScheme;
+  ThemeData(this.backgroundColor): colorScheme = ColorScheme(backgroundColor){}
+}
+
+class Color {
+  Color(int value) {}
+}
+
+class Colors {
+  Colors._();
+
+  static Color black = Color(0xFF000000);
+  static Color white = Color(0xFFFFFFFF);
+}
+
+class ColorScheme {
+    final Color background;
+    ColorScheme(this.background);
+}
+''');
+    addPackageDataFile('''
+version: 1
+transforms:
+  - title:  "Migrate to 'ColorScheme.background'"
+    date: 2020-09-24
+    element:
+      uris: ['$importUri']
+      field: 'backgroundColor'
+      inClass: 'ThemeData'
+    changes:
+      - kind: 'rename'
+        newName: 'colorScheme.background'
+''');
+    await resolveTestCode('''
+import '$importUri';
+
+void f() {
+  var themeData = ThemeData(Colors.black);
+  var color = themeData.backgroundColor;
+  print(color);
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+void f() {
+  var themeData = ThemeData(Colors.black);
+  var color = themeData.colorScheme.background;
+  print(color);
+}
+''');
+  }
+
+  Future<void> test_material_ThemeData_colorSchemeBackground_removed2() async {
+    setPackageContent('''
+
+class ThemeData {
+
+  final ColorScheme colorScheme;
+  ThemeData(this.backgroundColor): colorScheme = ColorScheme(backgroundColor){}
+}
+
+class Color {
+  Color(int value) {}
+}
+
+class Colors {
+  Colors._();
+
+  static Color black = Color(0xFF000000);
+  static Color white = Color(0xFFFFFFFF);
+}
+
+class ColorScheme {
+    final Color background;
+    ColorScheme(this.background);
+}
+''');
+    addPackageDataFile('''
+version: 1
+transforms:
+  - title:  "Migrate to 'ColorScheme.background'"
+    date: 2020-09-24
+    element:
+      uris: ['$importUri']
+      field: 'backgroundColor'
+      inClass: 'ThemeData'
+    changes:
+      - kind: 'rename'
+        newName: 'colorScheme.background'
+''');
+    await resolveTestCode('''
+import '$importUri';
+
+class T extends ThemeData {
+  T(Color color) : super(color);
+
+  void f() {
+    var color = backgroundColor;
+    print(color);
+  }
+}
+''');
+    await assertHasFix('''
+import '$importUri';
+
+class T extends ThemeData {
+  T(Color color) : super(color);
+
+  void f() {
+    var color = colorScheme.background;
+    print(color);
+  }
+}
+''');
+  }
+
+  Future<void>
       test_material_ThemeData_toggleableActiveColor_deprecated_1() async {
     setPackageContent('''