Skip to content

Commit 04e11b8

Browse files
srawlinsCommit Queue
authored andcommitted
DAS: Make CreateMethodOrFunction.fixKind final
With this change, CreateMethodOrFunction complies with the contract that `fixKind` not change before/after `compute()` is called. This change includes some tidying to simplify the code: * The decision of whether to use `DartFixKind.CREATE_METHOD` or `DartFixKind.CREATE_FUNCTION` is solely based on whether the "target element" is an InterfaceElement. So in the new factory constructor, we compute the "target element", and save that in a final field, as well as the fixKind. * `isStatic` was computed eagerly with other variables in a nest of else-if bodies. But it is only needed when creating a _method_, and so it's value can be computed nearer to where it is used. * `compute()` was ~100 lines long, and a lot of that code was dedicated to computing the parameter type. Intermediate values like `argument` and `parameterElement` sort of clutter the local variables; all of that code can be moved to a function that just computes the parameter type. Change-Id: Ibd5d96b752e7e03e52f585bb594c34331b08cdf1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/436861 Reviewed-by: Brian Wilkerson <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]>
1 parent d5bac65 commit 04e11b8

File tree

2 files changed

+129
-109
lines changed

2 files changed

+129
-109
lines changed

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

Lines changed: 124 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,57 @@ import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
1717
import 'package:analyzer_plugin/utilities/range_factory.dart';
1818

1919
class CreateMethodOrFunction extends ResolvedCorrectionProducer {
20-
FixKind _fixKind = DartFixKind.CREATE_METHOD;
20+
@override
21+
final FixKind fixKind;
2122

2223
String _functionName = '';
2324

24-
CreateMethodOrFunction({required super.context});
25+
/// The [Element] for the target of the node's parent, if that is a
26+
/// [PrefixedIdentifier] or [PropertyAccess], and `null` otherwise.
27+
final Element? _targetElement;
28+
29+
factory CreateMethodOrFunction({required CorrectionProducerContext context}) {
30+
if (context is StubCorrectionProducerContext) {
31+
return CreateMethodOrFunction._(context: context);
32+
}
33+
34+
if (context.node case SimpleIdentifier node) {
35+
// Prepare the argument expression (to get the parameter).
36+
Element? targetElement;
37+
var target = getQualifiedPropertyTarget(node);
38+
if (target == null) {
39+
targetElement = node.enclosingInterfaceElement;
40+
} else {
41+
var targetType = target.staticType;
42+
if (targetType is InterfaceType) {
43+
targetElement = targetType.element;
44+
} else {
45+
targetElement = switch (target) {
46+
SimpleIdentifier() => target.element,
47+
PrefixedIdentifier() => target.identifier.element,
48+
_ => null,
49+
};
50+
}
51+
}
52+
53+
return CreateMethodOrFunction._(
54+
context: context,
55+
targetElement: targetElement,
56+
fixKind:
57+
targetElement is InterfaceElement
58+
? DartFixKind.CREATE_METHOD
59+
: DartFixKind.CREATE_FUNCTION,
60+
);
61+
}
62+
63+
return CreateMethodOrFunction._(context: context);
64+
}
65+
66+
CreateMethodOrFunction._({
67+
required super.context,
68+
Element? targetElement,
69+
this.fixKind = DartFixKind.CREATE_METHOD,
70+
}) : _targetElement = targetElement;
2571

2672
@override
2773
CorrectionApplicability get applicability =>
@@ -31,103 +77,27 @@ class CreateMethodOrFunction extends ResolvedCorrectionProducer {
3177
@override
3278
List<String> get fixArguments => [_functionName];
3379

34-
@override
35-
FixKind get fixKind => _fixKind;
36-
3780
@override
3881
Future<void> compute(ChangeBuilder builder) async {
39-
var isStatic = false;
40-
var nameNode = node;
41-
if (nameNode is SimpleIdentifier) {
42-
// prepare argument expression (to get parameter)
43-
InterfaceElement? targetElement;
44-
Expression argument;
82+
if (node case SimpleIdentifier node) {
4583
var target = getQualifiedPropertyTarget(node);
46-
if (target != null) {
47-
var targetType = target.staticType;
48-
if (targetType is InterfaceType) {
49-
targetElement = targetType.element;
50-
argument = target.parent as Expression;
51-
} else if (target case SimpleIdentifier(
52-
:InterfaceElement? element,
53-
:Expression parent,
54-
)) {
55-
isStatic = true;
56-
targetElement = element;
57-
argument = parent;
58-
} else if (target
59-
case SimpleIdentifier identifier ||
60-
PrefixedIdentifier(:var identifier)) {
61-
if (identifier.element case InterfaceElement element) {
62-
isStatic = true;
63-
targetElement = element;
64-
argument = target.parent as Expression;
65-
} else {
66-
return;
67-
}
68-
} else {
69-
return;
70-
}
71-
} else {
72-
targetElement = node.enclosingInterfaceElement;
73-
argument = nameNode;
74-
}
75-
argument = stepUpNamedExpression(argument);
76-
// should be argument of some invocation
77-
// or child of an expression that is one
78-
var parameterElement = argument.correspondingParameter;
79-
int? recordFieldIndex;
80-
if (argument.parent case ConditionalExpression parent) {
81-
if (argument == parent.condition) {
82-
return;
83-
}
84-
parameterElement = parent.correspondingParameter;
85-
} else if (argument.parent case RecordLiteral record) {
86-
parameterElement = record.correspondingParameter;
87-
for (var (index, field)
88-
in record.fields.whereNotType<NamedExpression>().indexed) {
89-
if (field == argument) {
90-
recordFieldIndex = index;
91-
break;
92-
}
93-
}
94-
}
95-
if (parameterElement == null) {
96-
return;
97-
}
98-
// should be parameter of function type
99-
var parameterType = parameterElement.type;
100-
if (parameterType is RecordType) {
101-
// Finds the corresponding field for argument
102-
if (argument is NamedExpression) {
103-
var fieldName = argument.name.label.name;
104-
for (var field in parameterType.namedFields) {
105-
if (field.name == fieldName) {
106-
parameterType = field.type;
107-
break;
108-
}
109-
}
110-
} else if (recordFieldIndex != null) {
111-
var field = parameterType.positionalFields[recordFieldIndex];
112-
parameterType = field.type;
113-
}
114-
}
115-
if (parameterType is InterfaceType && parameterType.isDartCoreFunction) {
116-
parameterType = FunctionTypeImpl(
117-
typeFormals: const [],
118-
parameters: const [],
119-
returnType: DynamicTypeImpl.instance,
120-
nullabilitySuffix: NullabilitySuffix.none,
121-
);
122-
}
84+
85+
// In order to fix this by creating a function or a method,
86+
// `parameterType` should be be a function type.
87+
var parameterType = _computeParameterType(node, target);
12388
if (parameterType is! FunctionType) {
12489
return;
12590
}
126-
// add proposal
127-
if (targetElement != null) {
91+
92+
if (_targetElement is InterfaceElement) {
93+
var isStatic =
94+
(target is SimpleIdentifier &&
95+
target.element is InterfaceElement) ||
96+
(target is PrefixedIdentifier &&
97+
target.identifier.element is InterfaceElement);
12898
await _createMethod(
12999
builder,
130-
targetElement,
100+
_targetElement,
131101
parameterType,
132102
isStatic: isStatic,
133103
);
@@ -137,6 +107,69 @@ class CreateMethodOrFunction extends ResolvedCorrectionProducer {
137107
}
138108
}
139109

110+
DartType? _computeParameterType(SimpleIdentifier node, Expression? target) {
111+
// `argument` should be an argument of some invocation or child of an
112+
// expression that is one.
113+
Expression argument;
114+
if (target == null) {
115+
argument = node;
116+
} else {
117+
var targetParent = target.parent;
118+
if (targetParent is! Expression) {
119+
return null;
120+
}
121+
argument = targetParent;
122+
}
123+
argument = stepUpNamedExpression(argument);
124+
125+
var parameterElement = argument.correspondingParameter;
126+
int? recordFieldIndex;
127+
if (argument.parent case ConditionalExpression parent) {
128+
if (argument == parent.condition) {
129+
return null;
130+
}
131+
parameterElement = parent.correspondingParameter;
132+
} else if (argument.parent case RecordLiteral record) {
133+
parameterElement = record.correspondingParameter;
134+
for (var (index, field)
135+
in record.fields.whereNotType<NamedExpression>().indexed) {
136+
if (field == argument) {
137+
recordFieldIndex = index;
138+
break;
139+
}
140+
}
141+
}
142+
if (parameterElement == null) {
143+
return null;
144+
}
145+
146+
var parameterType = parameterElement.type;
147+
if (parameterType is RecordType) {
148+
// Finds the corresponding field for argument
149+
if (argument is NamedExpression) {
150+
var fieldName = argument.name.label.name;
151+
for (var field in parameterType.namedFields) {
152+
if (field.name == fieldName) {
153+
parameterType = field.type;
154+
break;
155+
}
156+
}
157+
} else if (recordFieldIndex != null) {
158+
var field = parameterType.positionalFields[recordFieldIndex];
159+
parameterType = field.type;
160+
}
161+
}
162+
if (parameterType is InterfaceType && parameterType.isDartCoreFunction) {
163+
return FunctionTypeImpl(
164+
typeFormals: const [],
165+
parameters: const [],
166+
returnType: DynamicTypeImpl.instance,
167+
nullabilitySuffix: NullabilitySuffix.none,
168+
);
169+
}
170+
return parameterType;
171+
}
172+
140173
/// Prepares proposal for creating function corresponding to the given
141174
/// [FunctionType].
142175
Future<void> _createExecutable(
@@ -211,7 +244,6 @@ class CreateMethodOrFunction extends ResolvedCorrectionProducer {
211244
sourcePrefix,
212245
sourceSuffix,
213246
);
214-
_fixKind = DartFixKind.CREATE_FUNCTION;
215247
_functionName = name;
216248
}
217249

@@ -270,7 +302,6 @@ class CreateMethodOrFunction extends ResolvedCorrectionProducer {
270302
sourcePrefix,
271303
sourceSuffix,
272304
);
273-
_fixKind = DartFixKind.CREATE_METHOD;
274305
_functionName = name;
275306
}
276307
}

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

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -258,22 +258,11 @@ List<AstNode> getParents(AstNode node) {
258258

259259
/// If given [node] is name of qualified property extraction, returns target
260260
/// from which this property is extracted, otherwise `null`.
261-
Expression? getQualifiedPropertyTarget(AstNode node) {
262-
var parent = node.parent;
263-
if (parent is PrefixedIdentifier) {
264-
var prefixed = parent;
265-
if (prefixed.identifier == node) {
266-
return parent.prefix;
267-
}
268-
}
269-
if (parent is PropertyAccess) {
270-
var access = parent;
271-
if (access.propertyName == node) {
272-
return access.realTarget;
273-
}
274-
}
275-
return null;
276-
}
261+
Expression? getQualifiedPropertyTarget(AstNode node) => switch (node.parent) {
262+
PrefixedIdentifier parent when parent.identifier == node => parent.prefix,
263+
PropertyAccess parent when parent.propertyName == node => parent.realTarget,
264+
_ => null,
265+
};
277266

278267
/// Returns the given [statement] if not a block, or the first child statement
279268
/// if a block, or `null` if more than one child.

0 commit comments

Comments
 (0)