Fix for searching references to named parameters in hierarchy.
R=brianwilkerson@google.com
Change-Id: I932eae1a1c6e440fab2034bffc7ec850f1216b9c
Reviewed-on: https://dart-review.googlesource.com/55841
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
diff --git a/pkg/analysis_server/lib/src/search/element_references.dart b/pkg/analysis_server/lib/src/search/element_references.dart
index 4b53584..fc60fb9 100644
--- a/pkg/analysis_server/lib/src/search/element_references.dart
+++ b/pkg/analysis_server/lib/src/search/element_references.dart
@@ -68,12 +68,15 @@
/**
* Returns a [Future] completing with [Element]s to search references to.
*
- * If a [ClassMemberElement] is given, each corresponding [Element] in the
- * hierarchy is returned.
+ * If a [ClassMemberElement] or a named [ParameterElement] is given, each
+ * corresponding [Element] in the hierarchy is returned.
*
* Otherwise, only references to [element] should be searched.
*/
Future<Iterable<Element>> _getRefElements(Element element) {
+ if (element is ParameterElement && element.isNamed) {
+ return getHierarchyNamedParameters(searchEngine, element);
+ }
if (element is ClassMemberElement) {
return getHierarchyMembers(searchEngine, element);
}
diff --git a/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart b/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
index 4b1c9eb4..eca6220 100644
--- a/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
+++ b/pkg/analysis_server/lib/src/services/refactoring/rename_local.dart
@@ -26,7 +26,7 @@
final AstProvider astProvider;
final ResolvedUnitCache unitCache;
- Set<LocalElement> elements = new Set<LocalElement>();
+ List<LocalElement> elements = [];
RenameLocalRefactoringImpl(
SearchEngine searchEngine, this.astProvider, LocalElement element)
@@ -92,25 +92,11 @@
* Fills [elements] with [Element]s to rename.
*/
Future _prepareElements() async {
- Element enclosing = element.enclosingElement;
- if (enclosing is MethodElement &&
- element is ParameterElement &&
- (element as ParameterElement).isNamed) {
- // prepare hierarchy methods
- Set<ClassMemberElement> methods =
- await getHierarchyMembers(searchEngine, enclosing);
- // add named parameter from each method
- for (ClassMemberElement method in methods) {
- if (method is MethodElement) {
- for (ParameterElement parameter in method.parameters) {
- if (parameter.isNamed && parameter.name == element.name) {
- elements.add(parameter);
- }
- }
- }
- }
+ Element element = this.element;
+ if (element is ParameterElement && element.isNamed) {
+ elements = await getHierarchyNamedParameters(searchEngine, element);
} else {
- elements = new Set.from([element]);
+ elements = [element];
}
}
}
diff --git a/pkg/analysis_server/lib/src/services/search/hierarchy.dart b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
index 3f9bb483..6441488 100644
--- a/pkg/analysis_server/lib/src/services/search/hierarchy.dart
+++ b/pkg/analysis_server/lib/src/services/search/hierarchy.dart
@@ -100,6 +100,34 @@
}
/**
+ * If the [element] is a named parameter in a [MethodElement], return all
+ * corresponding named parameters in the method hierarchy.
+ */
+Future<List<ParameterElement>> getHierarchyNamedParameters(
+ SearchEngine searchEngine, ParameterElement element) async {
+ if (element.isNamed) {
+ Element method = element.enclosingElement;
+ if (method is MethodElement) {
+ var hierarchyParameters = <ParameterElement>[];
+ var hierarchyMembers = await getHierarchyMembers(searchEngine, method);
+ for (ClassMemberElement hierarchyMethod in hierarchyMembers) {
+ if (hierarchyMethod is MethodElement) {
+ for (var hierarchyParameter in hierarchyMethod.parameters) {
+ if (hierarchyParameter.isNamed &&
+ hierarchyParameter.name == element.name) {
+ hierarchyParameters.add(hierarchyParameter);
+ break;
+ }
+ }
+ }
+ }
+ return hierarchyParameters;
+ }
+ }
+ return [element];
+}
+
+/**
* Returns non-synthetic members of the given [ClassElement] and its super
* classes.
*
diff --git a/pkg/analysis_server/test/search/element_references_test.dart b/pkg/analysis_server/test/search/element_references_test.dart
index 3e411f4..d320dbb 100644
--- a/pkg/analysis_server/test/search/element_references_test.dart
+++ b/pkg/analysis_server/test/search/element_references_test.dart
@@ -305,6 +305,30 @@
assertHasResult(SearchResultKind.INVOCATION, 'mmm(20)');
}
+ test_hierarchy_namedParameter() async {
+ addTestFile('''
+class A {
+ m({p}) {} // in A
+}
+class B extends A {
+ m({p}) {} // in B
+}
+class C extends B {
+ m({p}) {} // in C
+}
+main(A a, B b, C c) {
+ a.m(p: 1);
+ b.m(p: 2);
+ c.m(p: 3);
+}
+''');
+ await findElementReferences('p}) {} // in B', false);
+ expect(searchElement.kind, ElementKind.PARAMETER);
+ assertHasResult(SearchResultKind.REFERENCE, 'p: 1');
+ assertHasResult(SearchResultKind.REFERENCE, 'p: 2');
+ assertHasResult(SearchResultKind.REFERENCE, 'p: 3');
+ }
+
test_label() async {
addTestFile('''
main() {
diff --git a/pkg/analysis_server/test/services/search/hierarchy_test.dart b/pkg/analysis_server/test/services/search/hierarchy_test.dart
index d81893d..a6827ee 100644
--- a/pkg/analysis_server/test/services/search/hierarchy_test.dart
+++ b/pkg/analysis_server/test/services/search/hierarchy_test.dart
@@ -254,6 +254,95 @@
return Future.wait([futureA, futureB, futureD]);
}
+ test_getHierarchyNamedParameters() async {
+ await _indexTestUnit('''
+class A {
+ foo({p}) {}
+}
+class B extends A {
+ foo({p}) {}
+}
+class C extends B {
+ foo({p}) {}
+}
+class D {
+ foo({p}) {}
+}
+class E extends D {
+ foo({p}) {}
+}
+''');
+ ClassElement classA = findElement('A');
+ ClassElement classB = findElement('B');
+ ClassElement classC = findElement('C');
+ ClassElement classD = findElement('D');
+ ClassElement classE = findElement('E');
+ ParameterElement parameterA = classA.methods[0].parameters[0];
+ ParameterElement parameterB = classB.methods[0].parameters[0];
+ ParameterElement parameterC = classC.methods[0].parameters[0];
+ ParameterElement parameterD = classD.methods[0].parameters[0];
+ ParameterElement parameterE = classE.methods[0].parameters[0];
+
+ {
+ var result = await getHierarchyNamedParameters(searchEngine, parameterA);
+ expect(result, unorderedEquals([parameterA, parameterB, parameterC]));
+ }
+
+ {
+ var result = await getHierarchyNamedParameters(searchEngine, parameterB);
+ expect(result, unorderedEquals([parameterA, parameterB, parameterC]));
+ }
+
+ {
+ var result = await getHierarchyNamedParameters(searchEngine, parameterC);
+ expect(result, unorderedEquals([parameterA, parameterB, parameterC]));
+ }
+
+ {
+ var result = await getHierarchyNamedParameters(searchEngine, parameterD);
+ expect(result, unorderedEquals([parameterD, parameterE]));
+ }
+
+ {
+ var result = await getHierarchyNamedParameters(searchEngine, parameterE);
+ expect(result, unorderedEquals([parameterD, parameterE]));
+ }
+ }
+
+ test_getHierarchyNamedParameters_invalid_missing() async {
+ verifyNoTestUnitErrors = false;
+ await _indexTestUnit('''
+class A {
+ foo({p}) {}
+}
+class B extends A {
+ foo() {}
+}
+''');
+ ClassElement classA = findElement('A');
+ ParameterElement parameterA = classA.methods[0].parameters[0];
+
+ var result = await getHierarchyNamedParameters(searchEngine, parameterA);
+ expect(result, unorderedEquals([parameterA]));
+ }
+
+ test_getHierarchyNamedParameters_invalid_notNamed() async {
+ verifyNoTestUnitErrors = false;
+ await _indexTestUnit('''
+class A {
+ foo({p}) {}
+}
+class B extends A {
+ foo(p) {}
+}
+''');
+ ClassElement classA = findElement('A');
+ ParameterElement parameterA = classA.methods[0].parameters[0];
+
+ var result = await getHierarchyNamedParameters(searchEngine, parameterA);
+ expect(result, unorderedEquals([parameterA]));
+ }
+
test_getMembers() async {
await _indexTestUnit('''
class A {