Skip to content

Commit 82c3d74

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Renaming positional parameters to rename hierarchy equivalent
Fixes: #53187 Change-Id: Ie0aaea2e24667ad04a95ce6522fd687710501230 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/412520 Reviewed-by: Konstantin Shcheglov <[email protected]> Commit-Queue: Phil Quitslund <[email protected]> Auto-Submit: Felipe Morschel <[email protected]> Reviewed-by: Phil Quitslund <[email protected]>
1 parent 611e264 commit 82c3d74

File tree

11 files changed

+798
-379
lines changed

11 files changed

+798
-379
lines changed

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ import 'package:analysis_server/src/services/correction/util.dart';
88
import 'package:analysis_server/src/services/refactoring/legacy/refactoring.dart';
99
import 'package:analysis_server/src/services/refactoring/legacy/refactoring_internal.dart';
1010
import 'package:analysis_server/src/services/search/search_engine.dart';
11+
import 'package:analyzer/dart/analysis/code_style_options.dart';
1112
import 'package:analyzer/dart/element/element2.dart';
13+
import 'package:analyzer/file_system/file_system.dart';
1214
import 'package:analyzer/src/dart/analysis/session_helper.dart';
1315
import 'package:analyzer/src/dart/element/element.dart';
1416
import 'package:analyzer/src/generated/java_core.dart';
@@ -154,6 +156,11 @@ abstract class RenameRefactoringImpl extends RefactoringImpl
154156
/// Adds individual edits to [change].
155157
Future<void> fillChange();
156158

159+
CodeStyleOptions getCodeStyleOptions(File file) =>
160+
sessionHelper.session.analysisContext
161+
.getAnalysisOptionsForFile(file)
162+
.codeStyleOptions;
163+
157164
static String _getOldName(Element2 element) {
158165
if (element is ConstructorElement2) {
159166
var name = element.name3;

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

Lines changed: 30 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ import 'package:analyzer/dart/ast/visitor.dart';
1717
import 'package:analyzer/dart/element/element2.dart';
1818
import 'package:analyzer/source/source_range.dart';
1919
import 'package:analyzer/src/dart/element/element.dart';
20+
import 'package:analyzer/src/generated/java_core.dart';
2021

2122
class ConflictValidatorVisitor extends RecursiveAstVisitor<void> {
2223
final RefactoringStatus result;
@@ -88,7 +89,12 @@ class ConflictValidatorVisitor extends RecursiveAstVisitor<void> {
8889
if (_isVisibleWithTarget(declaredElement)) {
8990
conflictingLocals.add(declaredElement);
9091
var nodeKind = declaredElement.kind.displayName;
91-
var message = "Duplicate $nodeKind '$newName'.";
92+
var message = format(
93+
"Duplicate {0} of name '{1}'{2}.",
94+
nodeKind,
95+
newName,
96+
declaredElement.declarationLocation,
97+
);
9298
result.addError(message, newLocation_fromElement(declaredElement));
9399
return;
94100
}
@@ -200,3 +206,26 @@ class RenameLocalRefactoringImpl extends RenameRefactoringImpl {
200206
processor.addReferenceEdits(references);
201207
}
202208
}
209+
210+
extension on Element2 {
211+
String get declarationLocation {
212+
var sourceName = firstFragment.libraryFragment!.source.shortName;
213+
var executable = enclosingElement2;
214+
String className = '';
215+
String executableName = '';
216+
if (executable is MethodElement2) {
217+
var namescope = executable.enclosingElement2 as ClassElement2?;
218+
className = namescope?.displayName ?? '';
219+
if (className.isNotEmpty && executable.displayName.isNotEmpty) {
220+
className += '.';
221+
}
222+
executableName = executable.displayName;
223+
} else if (executable is TopLevelFunctionElement) {
224+
executableName = executable.displayName;
225+
}
226+
if (executableName.isEmpty) {
227+
return " in '$sourceName'";
228+
}
229+
return " at $className$executableName in '$sourceName'";
230+
}
231+
}

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

Lines changed: 63 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,12 @@ import 'package:analysis_server/src/services/refactoring/legacy/visible_ranges_c
1111
import 'package:analysis_server/src/services/search/hierarchy.dart';
1212
import 'package:analyzer/dart/element/element2.dart';
1313
import 'package:analyzer/src/generated/java_core.dart';
14+
import 'package:analyzer_plugin/protocol/protocol_common.dart';
1415

1516
/// A [Refactoring] for renaming [FormalParameterElement]s.
1617
class RenameParameterRefactoringImpl extends RenameRefactoringImpl {
1718
List<FormalParameterElement> elements = [];
19+
bool _renameAllPositionalOccurences = false;
1820

1921
RenameParameterRefactoringImpl(
2022
super.workspace,
@@ -33,6 +35,7 @@ class RenameParameterRefactoringImpl extends RenameRefactoringImpl {
3335
@override
3436
Future<RefactoringStatus> checkFinalConditions() async {
3537
var result = RefactoringStatus();
38+
var conflictResult = RefactoringStatus();
3639
await _prepareElements();
3740
for (var element in elements) {
3841
if (newName.startsWith('_') && element.isNamed) {
@@ -45,16 +48,39 @@ class RenameParameterRefactoringImpl extends RenameRefactoringImpl {
4548
break;
4649
}
4750
var resolvedUnit = await sessionHelper.getResolvedUnitByElement(element);
48-
var unit = resolvedUnit?.unit;
49-
unit?.accept(
50-
ConflictValidatorVisitor(
51-
result,
52-
newName,
53-
element,
54-
VisibleRangesComputer.forNode(unit),
51+
if (resolvedUnit != null) {
52+
// If any of the resolved units have the lint enabled, we should avoid
53+
// renaming method parameters separately from the other implementations.
54+
if (element.isPositional && !_renameAllPositionalOccurences) {
55+
_renameAllPositionalOccurences |=
56+
getCodeStyleOptions(
57+
resolvedUnit.file,
58+
).avoidRenamingMethodParameters;
59+
}
60+
61+
var unit = resolvedUnit.unit;
62+
unit.accept(
63+
ConflictValidatorVisitor(
64+
conflictResult,
65+
newName,
66+
element,
67+
VisibleRangesComputer.forNode(unit),
68+
),
69+
);
70+
}
71+
}
72+
if (_renameAllPositionalOccurences && elements.length > 1) {
73+
result.addStatus(
74+
_RefactoringStatusExt.from(
75+
'This will also rename all related positional parameters '
76+
'to the same name.',
77+
conflictResult,
5578
),
5679
);
5780
}
81+
if (result.problem == null) {
82+
return conflictResult;
83+
}
5884
return result;
5985
}
6086

@@ -69,6 +95,11 @@ class RenameParameterRefactoringImpl extends RenameRefactoringImpl {
6995
Future<void> fillChange() async {
7096
var processor = RenameProcessor(workspace, sessionHelper, change, newName);
7197
for (var element in elements) {
98+
if (element != this.element &&
99+
element.isPositional &&
100+
!_renameAllPositionalOccurences) {
101+
continue;
102+
}
72103
var fieldRenamed = false;
73104
if (element is FieldFormalParameterElement2) {
74105
var field = element.field2;
@@ -104,10 +135,31 @@ class RenameParameterRefactoringImpl extends RenameRefactoringImpl {
104135
Future<void> _prepareElements() async {
105136
var element = this.element;
106137
if (element.isNamed) {
107-
elements =
108-
(await getHierarchyNamedParameters(searchEngine, element)).toList();
109-
} else {
110-
elements = [element];
138+
elements = await getHierarchyNamedParameters(searchEngine, element);
139+
} else if (element.isPositional) {
140+
elements = await getHierarchyPositionalParameters(searchEngine, element);
111141
}
112142
}
113143
}
144+
145+
extension _RefactoringStatusExt on RefactoringStatus {
146+
String get messagesAggregated {
147+
if (problems.isEmpty) {
148+
return '';
149+
}
150+
if (problems.length == 1) {
151+
return '\n${problems.first.message}';
152+
}
153+
return '\n${problems.first.message} And ${problems.length - 1} more '
154+
'error${problems.length > 1 ? 's' : ''}.';
155+
}
156+
157+
static RefactoringStatus from(String message, RefactoringStatus result) {
158+
var constructor = switch (result.severity) {
159+
RefactoringProblemSeverity.ERROR => RefactoringStatus.error,
160+
RefactoringProblemSeverity.FATAL => RefactoringStatus.fatal,
161+
_ => RefactoringStatus.warning,
162+
};
163+
return constructor(message + result.messagesAggregated);
164+
}
165+
}

pkg/analysis_server/lib/src/services/search/hierarchy.dart

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,37 @@ Future<List<FormalParameterElement>> getHierarchyNamedParameters(
221221
return [element];
222222
}
223223

224+
Future<List<FormalParameterElement>> getHierarchyPositionalParameters(
225+
SearchEngine searchEngine,
226+
FormalParameterElement element,
227+
) async {
228+
if (element.isPositional) {
229+
var method = element.enclosingElement2;
230+
if (method is MethodElement2) {
231+
var index = method.parameterIndex(element);
232+
// Should not ever happen but this means we can't find the index.
233+
if (index == null) {
234+
return [element];
235+
}
236+
var hierarchyParameters = <FormalParameterElement>[];
237+
var hierarchyMembers = await getHierarchyMembers(searchEngine, method);
238+
for (var hierarchyMethod in hierarchyMembers) {
239+
if (hierarchyMethod is MethodElement2) {
240+
for (var hierarchyParameter in hierarchyMethod.formalParameters) {
241+
if (hierarchyParameter.isPositional &&
242+
hierarchyMethod.parameterIndex(hierarchyParameter) == index) {
243+
hierarchyParameters.add(hierarchyParameter);
244+
break;
245+
}
246+
}
247+
}
248+
}
249+
return hierarchyParameters;
250+
}
251+
}
252+
return [element];
253+
}
254+
224255
/// Returns non-synthetic members of the given [InterfaceElement2] and its super
225256
/// classes.
226257
///
@@ -254,3 +285,18 @@ String? _getBaseName(Element2 element) {
254285
}
255286
return element.name3;
256287
}
288+
289+
extension on MethodElement2 {
290+
int? parameterIndex(FormalParameterElement parameter) {
291+
var index = 0;
292+
for (var positionalParameter in formalParameters.where(
293+
(p) => p.isPositional,
294+
)) {
295+
if (positionalParameter == parameter) {
296+
return index;
297+
}
298+
index++;
299+
}
300+
return null;
301+
}
302+
}

pkg/analysis_server/test/edit/refactoring_test.dart

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2739,7 +2739,7 @@ void f() {
27392739
expect(problems, hasLength(1));
27402740
assertResultProblemsError(
27412741
problems,
2742-
"Duplicate local variable 'newName'.",
2742+
"Duplicate local variable of name 'newName' at f in 'test.dart'.",
27432743
);
27442744
});
27452745
}

0 commit comments

Comments
 (0)