Skip to content

Commit 2175df0

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Adds new create operator fix
Fixes: #60954 Change-Id: I933e45ddd950b798e87595f4de8a5cadabddf898 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/435660 Auto-Submit: Felipe Morschel <[email protected]> Commit-Queue: Samuel Rawlins <[email protected]> Reviewed-by: Paul Berry <[email protected]> Reviewed-by: Samuel Rawlins <[email protected]>
1 parent af7397b commit 2175df0

File tree

6 files changed

+841
-1
lines changed

6 files changed

+841
-1
lines changed
Lines changed: 173 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,173 @@
1+
// Copyright (c) 2025, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'package:analysis_server/src/services/correction/fix.dart';
6+
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
7+
import 'package:analyzer/dart/analysis/results.dart';
8+
import 'package:analyzer/dart/ast/token.dart';
9+
import 'package:analyzer/dart/element/element.dart';
10+
import 'package:analyzer/dart/element/type.dart';
11+
import 'package:analyzer/src/dart/ast/ast.dart';
12+
import 'package:analyzer/src/dart/element/type.dart';
13+
import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dart';
14+
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
15+
16+
class CreateOperator extends ResolvedCorrectionProducer {
17+
String _operator = '';
18+
19+
CreateOperator({required super.context});
20+
21+
@override
22+
CorrectionApplicability get applicability {
23+
// Not predictably the correct action.
24+
return CorrectionApplicability.singleLocation;
25+
}
26+
27+
@override
28+
List<String>? get fixArguments => [_operator];
29+
30+
@override
31+
FixKind get fixKind => DartFixKind.CREATE_OPERATOR;
32+
33+
@override
34+
Future<void> compute(ChangeBuilder builder) async {
35+
bool indexSetter = false;
36+
bool innerParameter = true;
37+
var node = this.node;
38+
if (node is! Expression) {
39+
return;
40+
}
41+
42+
Expression? target;
43+
DartType? parameterType;
44+
Fragment? targetFragment;
45+
DartType? assigningType;
46+
CompilationUnitMember? targetNode;
47+
48+
switch (node) {
49+
case IndexExpression(:var parent):
50+
target = node.target;
51+
_operator = TokenType.INDEX.lexeme;
52+
parameterType = node.index.staticType;
53+
if (parameterType == null) {
54+
return;
55+
}
56+
if (parent case AssignmentExpression(
57+
:var leftHandSide,
58+
:var rightHandSide,
59+
) when leftHandSide == node) {
60+
assigningType = rightHandSide.staticType;
61+
indexSetter = true;
62+
_operator = TokenType.INDEX_EQ.lexeme;
63+
}
64+
case BinaryExpression():
65+
target = node.leftOperand;
66+
_operator = node.operator.lexeme;
67+
parameterType = node.rightOperand.staticType;
68+
if (parameterType == null) {
69+
return;
70+
}
71+
case PrefixExpression():
72+
target = node.operand;
73+
_operator = node.operator.lexeme;
74+
innerParameter = false;
75+
}
76+
77+
if (target == null) {
78+
return;
79+
}
80+
81+
// We need the type for the extension.
82+
var targetType = target.staticType;
83+
if (targetType == null ||
84+
targetType is DynamicType ||
85+
targetType is InvalidType) {
86+
return;
87+
}
88+
89+
DartType returnType;
90+
// If this is an index setter, the return type must be void.
91+
if (indexSetter) {
92+
returnType = VoidTypeImpl.instance;
93+
} else {
94+
// Try to find the return type.
95+
returnType = inferUndefinedExpressionType(node) ?? VoidTypeImpl.instance;
96+
}
97+
98+
var targetClassElement = getTargetInterfaceElement(target);
99+
if (targetClassElement == null) {
100+
return;
101+
}
102+
targetFragment = targetClassElement.firstFragment;
103+
if (targetClassElement.library2.isInSdk) {
104+
return;
105+
}
106+
// Prepare target ClassDeclaration.
107+
if (targetClassElement is MixinElement) {
108+
var fragment = targetClassElement.firstFragment;
109+
targetNode = await getMixinDeclaration(fragment);
110+
} else if (targetClassElement is ClassElement) {
111+
var fragment = targetClassElement.firstFragment;
112+
targetNode = await getClassDeclaration(fragment);
113+
} else if (targetClassElement is ExtensionTypeElement) {
114+
var fragment = targetClassElement.firstFragment;
115+
targetNode = await getExtensionTypeDeclaration(fragment);
116+
} else if (targetClassElement is EnumElement) {
117+
var fragment = targetClassElement.firstFragment;
118+
targetNode = await getEnumDeclaration(fragment);
119+
}
120+
if (targetNode == null) {
121+
return;
122+
}
123+
// Use different utils.
124+
var targetPath = targetFragment.libraryFragment!.source.fullName;
125+
var targetResolveResult = await unitResult.session.getResolvedUnit(
126+
targetPath,
127+
);
128+
if (targetResolveResult is! ResolvedUnitResult) {
129+
return;
130+
}
131+
var targetSource = targetFragment.libraryFragment!.source;
132+
var targetFile = targetSource.fullName;
133+
134+
var writeReturnType =
135+
getCodeStyleOptions(unitResult.file).specifyReturnTypes;
136+
137+
if (returnType is TypeParameterType) {
138+
returnType = returnType.bound;
139+
}
140+
141+
await builder.addDartFileEdit(targetFile, (builder) {
142+
if (targetNode == null) {
143+
return;
144+
}
145+
builder.insertMethod(targetNode, (builder) {
146+
// Append return type.
147+
builder.writeType(returnType, shouldWriteDynamic: writeReturnType);
148+
if ((returnType is! DynamicType && returnType is! InvalidType) ||
149+
writeReturnType) {
150+
builder.write(' ');
151+
}
152+
builder.write('operator ');
153+
builder.write(_operator);
154+
// Append parameters.
155+
if (innerParameter) {
156+
builder.write('(');
157+
builder.writeParameter('other', type: parameterType);
158+
if (assigningType != null) {
159+
builder.write(', ');
160+
builder.writeParameter('value', type: assigningType);
161+
}
162+
builder.write(')');
163+
} else {
164+
builder.write('()');
165+
}
166+
if (returnType.isDartAsyncFuture) {
167+
builder.write(' async');
168+
}
169+
builder.write(' {}');
170+
});
171+
});
172+
}
173+
}

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

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -855,6 +855,11 @@ abstract final class DartFixKind {
855855
DartFixKindPriority.standard - 1,
856856
"Create 'noSuchMethod' method",
857857
);
858+
static const CREATE_OPERATOR = FixKind(
859+
'dart.fix.create.operator',
860+
DartFixKindPriority.standard,
861+
"Create operator '{0}'",
862+
);
858863
static const CREATE_PARAMETER = FixKind(
859864
'dart.fix.create.parameter',
860865
DartFixKindPriority.standard,

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ import 'package:analysis_server/src/services/correction/dart/create_method_or_fu
101101
import 'package:analysis_server/src/services/correction/dart/create_missing_overrides.dart';
102102
import 'package:analysis_server/src/services/correction/dart/create_mixin.dart';
103103
import 'package:analysis_server/src/services/correction/dart/create_no_such_method.dart';
104+
import 'package:analysis_server/src/services/correction/dart/create_operator.dart';
104105
import 'package:analysis_server/src/services/correction/dart/create_parameter.dart';
105106
import 'package:analysis_server/src/services/correction/dart/create_setter.dart';
106107
import 'package:analysis_server/src/services/correction/dart/data_driven.dart';
@@ -918,6 +919,7 @@ final _builtInNonLintGenerators = <DiagnosticCode, List<ProducerGenerator>>{
918919
CompileTimeErrorCode.UNCHECKED_OPERATOR_INVOCATION_OF_NULLABLE_VALUE: [
919920
AddNullCheck.new,
920921
CreateExtensionOperator.new,
922+
CreateOperator.new,
921923
],
922924
CompileTimeErrorCode.UNCHECKED_PROPERTY_ACCESS_OF_NULLABLE_VALUE: [
923925
AddNullCheck.new,
@@ -1002,7 +1004,10 @@ final _builtInNonLintGenerators = <DiagnosticCode, List<ProducerGenerator>>{
10021004
ConvertFlutterChild.new,
10031005
ConvertFlutterChildren.new,
10041006
],
1005-
CompileTimeErrorCode.UNDEFINED_OPERATOR: [CreateExtensionOperator.new],
1007+
CompileTimeErrorCode.UNDEFINED_OPERATOR: [
1008+
CreateExtensionOperator.new,
1009+
CreateOperator.new,
1010+
],
10061011
CompileTimeErrorCode.UNDEFINED_SETTER: [
10071012
ChangeTo.getterOrSetter,
10081013
CreateExtensionSetter.new,

0 commit comments

Comments
 (0)