Skip to content

Commit 4e432bd

Browse files
kallentuCommit Queue
authored andcommitted
[analysis_server] Dot shorthands: Update CreateMethod fix.
Refactored `CreateMethod` to handle both method invocations and dot shorthand invocations. The code overlaps so a lot of the CL is just re-organizing them into helpers. Added unit tests. Bug: #60994 Change-Id: Ie06005b67f0fe5f066ab57a2f0dbc06095597897 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/442729 Commit-Queue: Kallen Tu <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 6a534c6 commit 4e432bd

File tree

2 files changed

+255
-49
lines changed

2 files changed

+255
-49
lines changed

pkg/analysis_server/lib/src/services/correction/dart/create_method.dart

Lines changed: 91 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@
33
// BSD-style license that can be found in the LICENSE file.
44

55
import 'package:analysis_server/src/services/correction/fix.dart';
6+
import 'package:analysis_server/src/services/correction/util.dart';
67
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
7-
import 'package:analyzer/dart/analysis/results.dart';
88
import 'package:analyzer/dart/ast/ast.dart';
99
import 'package:analyzer/dart/element/element.dart';
1010
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
@@ -88,14 +88,48 @@ class CreateMethod extends ResolvedCorrectionProducer {
8888
}
8989

9090
Future<void> _createMethod(ChangeBuilder builder) async {
91-
if (node is! SimpleIdentifier || node.parent is! MethodInvocation) {
92-
return;
93-
}
91+
if (node is! SimpleIdentifier) return;
9492
_memberName = (node as SimpleIdentifier).name;
95-
var invocation = node.parent as MethodInvocation;
93+
94+
var invocation = node.parent;
95+
switch (invocation) {
96+
case MethodInvocation():
97+
await _createMethodFromMethodInvocation(builder, invocation);
98+
case DotShorthandInvocation():
99+
await _createMethodFromDotShorthandInvocation(builder, invocation);
100+
}
101+
}
102+
103+
Future<void> _createMethodFromDotShorthandInvocation(
104+
ChangeBuilder builder,
105+
DotShorthandInvocation invocation,
106+
) async {
107+
var targetClassElement = computeDotShorthandContextTypeElement(
108+
invocation,
109+
unitResult.libraryElement,
110+
);
111+
if (targetClassElement == null) return;
112+
113+
var targetNode = await _declarationNodeFromElement(targetClassElement);
114+
if (targetNode is! CompilationUnitMember) return;
115+
116+
await _writeMethod(
117+
builder,
118+
invocation,
119+
invocation.argumentList,
120+
targetClassElement.firstFragment,
121+
targetNode,
122+
hasStaticModifier: true,
123+
);
124+
}
125+
126+
Future<void> _createMethodFromMethodInvocation(
127+
ChangeBuilder builder,
128+
MethodInvocation invocation,
129+
) async {
96130
// Prepare environment.
97131
Fragment? targetFragment;
98-
var staticModifier = false;
132+
var hasStaticModifier = false;
99133

100134
CompilationUnitMember? targetNode;
101135
var target = invocation.realTarget;
@@ -117,7 +151,7 @@ class CreateMethod extends ResolvedCorrectionProducer {
117151
if (enclosingMemberParent is CompilationUnitMember &&
118152
enclosingMemberParent is! ExtensionDeclaration) {
119153
targetNode = enclosingMemberParent;
120-
staticModifier = switch (enclosingMember) {
154+
hasStaticModifier = switch (enclosingMember) {
121155
ConstructorDeclaration(:var factoryKeyword) => factoryKeyword != null,
122156
MethodDeclaration(:var isStatic) => isStatic,
123157
FieldDeclaration(
@@ -129,64 +163,72 @@ class CreateMethod extends ResolvedCorrectionProducer {
129163
}
130164
} else {
131165
var targetClassElement = getTargetInterfaceElement(target);
132-
if (targetClassElement == null) {
133-
return;
134-
}
166+
if (targetClassElement == null) return;
135167
targetFragment = targetClassElement.firstFragment;
136-
if (targetClassElement.library.isInSdk) {
137-
return;
138-
}
139-
// Prepare target ClassDeclaration.
140-
if (targetClassElement is MixinElement) {
141-
var fragment = targetClassElement.firstFragment;
142-
targetNode = await getMixinDeclaration(fragment);
143-
} else if (targetClassElement is ClassElement) {
144-
var fragment = targetClassElement.firstFragment;
145-
targetNode = await getClassDeclaration(fragment);
146-
} else if (targetClassElement is ExtensionTypeElement) {
147-
var fragment = targetClassElement.firstFragment;
148-
targetNode = await getExtensionTypeDeclaration(fragment);
149-
} else if (targetClassElement is EnumElement) {
150-
var fragment = targetClassElement.firstFragment;
151-
targetNode = await getEnumDeclaration(fragment);
152-
}
153-
if (targetNode == null) {
154-
return;
155-
}
168+
169+
targetNode = await _declarationNodeFromElement(targetClassElement);
170+
if (targetNode == null) return;
171+
156172
// Maybe static.
157173
if (target is Identifier) {
158-
staticModifier =
174+
hasStaticModifier =
159175
target.element?.kind == ElementKind.CLASS ||
160176
target.element?.kind == ElementKind.ENUM ||
161177
target.element?.kind == ElementKind.EXTENSION_TYPE ||
162178
target.element?.kind == ElementKind.MIXIN;
163179
}
164-
// Use different utils.
165-
var targetPath = targetFragment.libraryFragment!.source.fullName;
166-
var targetResolveResult = await unitResult.session.getResolvedUnit(
167-
targetPath,
168-
);
169-
if (targetResolveResult is! ResolvedUnitResult) {
170-
return;
171-
}
172180
}
173-
var targetSource = targetFragment?.libraryFragment!.source;
174-
if (targetSource == null) {
175-
return;
181+
await _writeMethod(
182+
builder,
183+
invocation,
184+
invocation.argumentList,
185+
targetFragment,
186+
targetNode,
187+
hasStaticModifier: hasStaticModifier,
188+
);
189+
}
190+
191+
Future<CompilationUnitMember?> _declarationNodeFromElement(
192+
InterfaceElement element,
193+
) async {
194+
if (element.library.isInSdk) return null;
195+
if (element is MixinElement) {
196+
var fragment = element.firstFragment;
197+
return await getMixinDeclaration(fragment);
198+
} else if (element is ClassElement) {
199+
var fragment = element.firstFragment;
200+
return await getClassDeclaration(fragment);
201+
} else if (element is ExtensionTypeElement) {
202+
var fragment = element.firstFragment;
203+
return await getExtensionTypeDeclaration(fragment);
204+
} else if (element is EnumElement) {
205+
var fragment = element.firstFragment;
206+
return await getEnumDeclaration(fragment);
176207
}
208+
return null;
209+
}
210+
211+
/// Inserts the new method into the source code.
212+
Future<void> _writeMethod(
213+
ChangeBuilder builder,
214+
Expression invocation,
215+
ArgumentList argumentList,
216+
Fragment? targetFragment,
217+
CompilationUnitMember? targetNode, {
218+
required bool hasStaticModifier,
219+
}) async {
220+
var targetSource = targetFragment?.libraryFragment!.source;
221+
if (targetSource == null) return;
222+
177223
var targetFile = targetSource.fullName;
178-
// Build method source.
179224
await builder.addDartFileEdit(targetFile, (builder) {
180-
if (targetNode == null) {
181-
return;
182-
}
225+
if (targetNode == null) return;
183226
builder.insertMethod(targetNode, (builder) {
184227
// Maybe 'static'.
185-
if (staticModifier) {
228+
if (hasStaticModifier) {
186229
builder.write('static ');
187230
}
188231
// Append return type.
189-
190232
var type = inferUndefinedExpressionType(invocation);
191233
if (builder.writeType(type, groupName: 'RETURN_TYPE')) {
192234
builder.write(' ');
@@ -197,7 +239,7 @@ class CreateMethod extends ResolvedCorrectionProducer {
197239
builder.write(_memberName);
198240
});
199241
builder.write('(');
200-
builder.writeParametersMatchingArguments(invocation.argumentList);
242+
builder.writeParametersMatchingArguments(argumentList);
201243
builder.write(')');
202244
if (type?.isDartAsyncFuture == true) {
203245
builder.write(' async');

0 commit comments

Comments
 (0)