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('''