Skip to content

Commit 34fcc56

Browse files
scheglovcommit-bot@chromium.org
authored andcommitted
Fix for renaming named formal parameters from invocations, when synthetic.
[email protected] Change-Id: I4dc57cfc2a941229f2ba8b8b262ed49ecdd6b170 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/137825 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Konstantin Shcheglov <[email protected]>
1 parent 6708f6d commit 34fcc56

File tree

5 files changed

+177
-0
lines changed

5 files changed

+177
-0
lines changed

pkg/analysis_server/lib/src/services/refactoring/refactoring.dart

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ import 'package:analyzer/dart/ast/ast.dart';
2828
import 'package:analyzer/dart/element/element.dart';
2929
import 'package:analyzer/file_system/file_system.dart';
3030
import 'package:analyzer/src/dart/analysis/driver.dart';
31+
import 'package:analyzer/src/dart/analysis/index.dart';
3132
import 'package:analyzer_plugin/protocol/protocol_common.dart'
3233
show RefactoringMethodParameter, SourceChange;
3334

@@ -384,6 +385,10 @@ abstract class RenameRefactoring implements Refactoring {
384385
int offset = node.offset;
385386
int length = node.length;
386387

388+
if (node is SimpleIdentifier && element is ParameterElement) {
389+
element = declaredParameterElement(node, element);
390+
}
391+
387392
if (element is FieldFormalParameterElement) {
388393
element = (element as FieldFormalParameterElement).field;
389394
}

pkg/analysis_server/test/edit/refactoring_test.dart

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1845,6 +1845,52 @@ main() {
18451845
});
18461846
}
18471847

1848+
Future<void> test_formalParameter_named_ofConstructor_genericClass() {
1849+
addTestFile('''
1850+
class A<T> {
1851+
A({T test});
1852+
}
1853+
1854+
main() {
1855+
A(test: 0);
1856+
}
1857+
''');
1858+
return assertSuccessfulRefactoring(() {
1859+
return sendRenameRequest('test: 0', 'newName');
1860+
}, '''
1861+
class A<T> {
1862+
A({T newName});
1863+
}
1864+
1865+
main() {
1866+
A(newName: 0);
1867+
}
1868+
''');
1869+
}
1870+
1871+
Future<void> test_formalParameter_named_ofMethod_genericClass() {
1872+
addTestFile('''
1873+
class A<T> {
1874+
void foo({T test}) {}
1875+
}
1876+
1877+
main(A<int> a) {
1878+
a.foo(test: 0);
1879+
}
1880+
''');
1881+
return assertSuccessfulRefactoring(() {
1882+
return sendRenameRequest('test: 0', 'newName');
1883+
}, '''
1884+
class A<T> {
1885+
void foo({T newName}) {}
1886+
}
1887+
1888+
main(A<int> a) {
1889+
a.foo(newName: 0);
1890+
}
1891+
''');
1892+
}
1893+
18481894
Future<void> test_function() {
18491895
addTestFile('''
18501896
test() {}

pkg/analysis_server/test/services/refactoring/rename_local_test.dart

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -491,6 +491,61 @@ main() {
491491
''');
492492
}
493493

494+
Future<void>
495+
test_createChange_parameter_named_ofConstructor_genericClass() async {
496+
await indexTestUnit('''
497+
class A<T> {
498+
A({T test});
499+
}
500+
501+
main() {
502+
A(test: 0);
503+
}
504+
''');
505+
// configure refactoring
506+
createRenameRefactoringAtString('test}');
507+
expect(refactoring.refactoringName, 'Rename Parameter');
508+
expect(refactoring.elementKindName, 'parameter');
509+
refactoring.newName = 'newName';
510+
// validate change
511+
return assertSuccessfulRefactoring('''
512+
class A<T> {
513+
A({T newName});
514+
}
515+
516+
main() {
517+
A(newName: 0);
518+
}
519+
''');
520+
}
521+
522+
Future<void> test_createChange_parameter_named_ofMethod_genericClass() async {
523+
await indexTestUnit('''
524+
class A<T> {
525+
void foo({T test}) {}
526+
}
527+
528+
main(A<int> a) {
529+
a.foo(test: 0);
530+
}
531+
''');
532+
// configure refactoring
533+
createRenameRefactoringAtString('test}');
534+
expect(refactoring.refactoringName, 'Rename Parameter');
535+
expect(refactoring.elementKindName, 'parameter');
536+
refactoring.newName = 'newName';
537+
// validate change
538+
return assertSuccessfulRefactoring('''
539+
class A<T> {
540+
void foo({T newName}) {}
541+
}
542+
543+
main(A<int> a) {
544+
a.foo(newName: 0);
545+
}
546+
''');
547+
}
548+
494549
Future<void> test_createChange_parameter_named_updateHierarchy() async {
495550
await indexUnit('/home/test/lib/test2.dart', '''
496551
library test2;

pkg/analyzer/lib/src/dart/analysis/index.dart

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,44 @@ import 'package:analyzer/dart/element/type.dart';
1010
import 'package:analyzer/src/summary/format.dart';
1111
import 'package:analyzer/src/summary/idl.dart';
1212

13+
Element declaredParameterElement(
14+
SimpleIdentifier node,
15+
Element element,
16+
) {
17+
if (element.enclosingElement != null) {
18+
return element;
19+
}
20+
21+
/// When we instantiate the [FunctionType] of an executable, we use
22+
/// synthetic [ParameterElement]s, disconnected from the rest of the
23+
/// element model. But we want to index these parameter references
24+
/// as references to declared parameters.
25+
ParameterElement namedParameterElement(ExecutableElement executable) {
26+
var parameterName = node.name;
27+
return executable.declaration.parameters.where((parameter) {
28+
return parameter.isNamed && parameter.name == parameterName;
29+
}).first;
30+
}
31+
32+
var parent = node.parent;
33+
if (parent is Label && parent.label == node) {
34+
var namedExpression = parent.parent;
35+
if (namedExpression is NamedExpression && namedExpression.name == parent) {
36+
var argumentList = namedExpression.parent;
37+
if (argumentList is ArgumentList) {
38+
var invocation = argumentList.parent;
39+
if (invocation is InstanceCreationExpression) {
40+
return namedParameterElement(invocation.staticElement);
41+
} else if (invocation is MethodInvocation) {
42+
return namedParameterElement(invocation.methodName.staticElement);
43+
}
44+
}
45+
}
46+
}
47+
48+
return element;
49+
}
50+
1351
/**
1452
* Return the [CompilationUnitElement] that should be used for [element].
1553
* Throw [StateError] if the [element] is not linked into a unit.
@@ -719,7 +757,12 @@ class _IndexContributor extends GeneralizingAstVisitor {
719757
if (node.inDeclarationContext()) {
720758
return;
721759
}
760+
722761
Element element = node.staticElement;
762+
if (node is SimpleIdentifier && element is ParameterElement) {
763+
element = declaredParameterElement(node, element);
764+
}
765+
723766
// record unresolved name reference
724767
bool isQualified = _isQualified(node);
725768
if (element == null) {

pkg/analyzer/test/src/dart/analysis/index_test.dart

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,34 @@ main() {
906906
assertThat(element)..isReferencedAt('p: 1', true);
907907
}
908908

909+
test_isReferencedBy_ParameterElement_named_ofMethod_genericClass() async {
910+
await _indexTestUnit('''
911+
class A<T> {
912+
void foo({T test}) {}
913+
}
914+
915+
main(A<int> a) {
916+
a.foo(test: 0);
917+
}
918+
''');
919+
Element element = findElement('test');
920+
assertThat(element)..isReferencedAt('test: 0', true);
921+
}
922+
923+
test_isReferencedBy_ParameterElement_named_ofConstructor_genericClass() async {
924+
await _indexTestUnit('''
925+
class A<T> {
926+
A({T test});
927+
}
928+
929+
main() {
930+
A(test: 0);
931+
}
932+
''');
933+
Element element = findElement('test');
934+
assertThat(element)..isReferencedAt('test: 0', true);
935+
}
936+
909937
test_isReferencedBy_ParameterElement_genericFunctionType() async {
910938
await _indexTestUnit('''
911939
typedef F = void Function({int p});

0 commit comments

Comments
 (0)