Skip to content

Commit bc4e201

Browse files
FMorschelCommit Queue
authored andcommitted
[DAS] Fixes missing case for create class
This also adds a new priority for mixins when the written type name starts with lowercase letters (to match the class existing ones) and tests the priority between it, create class and import fixes. Fixes: #60874 Change-Id: Ie451db6a273fe8eb52df21725276068b1980e7f1 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/433500 Commit-Queue: Brian Wilkerson <[email protected]> Auto-Submit: Felipe Morschel <[email protected]> Reviewed-by: Samuel Rawlins <[email protected]> Reviewed-by: Brian Wilkerson <[email protected]>
1 parent 6f076f9 commit bc4e201

File tree

8 files changed

+425
-61
lines changed

8 files changed

+425
-61
lines changed

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

Lines changed: 21 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
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/utilities/extensions/string.dart';
67
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
78
import 'package:analyzer/dart/ast/ast.dart';
89
import 'package:analyzer/dart/element/element.dart';
@@ -12,8 +13,6 @@ import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
1213
import 'package:analyzer_plugin/utilities/range_factory.dart';
1314

1415
class CreateClass extends MultiCorrectionProducer {
15-
static final _lowerCaseRegex = RegExp(r'([_\$]||[_\$]+[0-9])*[a-z]');
16-
1716
CreateClass({required super.context});
1817

1918
@override
@@ -22,6 +21,7 @@ class CreateClass extends MultiCorrectionProducer {
2221
Element? prefixElement;
2322
ArgumentList? arguments;
2423

24+
var withKeyword = false;
2525
String? className;
2626
bool requiresConstConstructor = false;
2727
if (targetNode is Annotation) {
@@ -43,13 +43,19 @@ class CreateClass extends MultiCorrectionProducer {
4343
return const [];
4444
}
4545
}
46+
withKeyword = node.parent is WithClause;
4647
className = targetNode.name.lexeme;
4748
requiresConstConstructor |= _requiresConstConstructor(targetNode);
4849
} else if (targetNode case SimpleIdentifier(
4950
:var parent,
5051
) when parent is! PropertyAccess && parent is! PrefixedIdentifier) {
5152
className = targetNode.nameOfType ?? targetNode.name;
5253
requiresConstConstructor |= _requiresConstConstructor(targetNode);
54+
} else if (targetNode case SimpleIdentifier(
55+
parent: PrefixedIdentifier(:var identifier),
56+
) when targetNode != identifier) {
57+
className = targetNode.nameOfType ?? targetNode.name;
58+
requiresConstConstructor |= _requiresConstConstructor(targetNode);
5359
} else if (targetNode is PrefixedIdentifier) {
5460
prefixElement = targetNode.prefix.element;
5561
if (prefixElement == null) {
@@ -65,14 +71,15 @@ class CreateClass extends MultiCorrectionProducer {
6571
return const [];
6672
}
6773
// Lowercase class names are valid but not idiomatic so lower the priority.
68-
if (className.startsWith(_lowerCaseRegex)) {
74+
if (className.firstLetterIsLowercase) {
6975
return [
7076
_CreateClass.lowercase(
7177
context: context,
7278
targetNode: targetNode,
7379
prefixElement: prefixElement,
7480
className: className,
7581
requiresConstConstructor: requiresConstConstructor,
82+
withKeyword: withKeyword,
7683
arguments: arguments,
7784
),
7885
];
@@ -84,6 +91,7 @@ class CreateClass extends MultiCorrectionProducer {
8491
prefixElement: prefixElement,
8592
className: className,
8693
requiresConstConstructor: requiresConstConstructor,
94+
withKeyword: withKeyword,
8795
arguments: arguments,
8896
),
8997
];
@@ -126,12 +134,16 @@ class _CreateClass extends ResolvedCorrectionProducer {
126134
required AstNode targetNode,
127135
required Element? prefixElement,
128136
required String className,
137+
required bool withKeyword,
129138
}) : _className = className,
130139
_prefixElement = prefixElement,
131140
_targetNode = targetNode,
132141
_requiresConstConstructor = requiresConstConstructor,
133142
_arguments = arguments,
134-
fixKind = DartFixKind.CREATE_CLASS_LOWERCASE;
143+
fixKind =
144+
withKeyword
145+
? DartFixKind.CREATE_CLASS_LOWERCASE_WITH
146+
: DartFixKind.CREATE_CLASS_LOWERCASE;
135147

136148
_CreateClass.uppercase({
137149
required super.context,
@@ -140,12 +152,16 @@ class _CreateClass extends ResolvedCorrectionProducer {
140152
required AstNode targetNode,
141153
required Element? prefixElement,
142154
required String className,
155+
required bool withKeyword,
143156
}) : _className = className,
144157
_prefixElement = prefixElement,
145158
_targetNode = targetNode,
146159
_requiresConstConstructor = requiresConstConstructor,
147160
_arguments = arguments,
148-
fixKind = DartFixKind.CREATE_CLASS_UPPERCASE;
161+
fixKind =
162+
withKeyword
163+
? DartFixKind.CREATE_CLASS_UPPERCASE_WITH
164+
: DartFixKind.CREATE_CLASS_UPPERCASE;
149165

150166
@override
151167
CorrectionApplicability get applicability =>

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

Lines changed: 80 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
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/utilities/extensions/string.dart';
67
import 'package:analysis_server_plugin/edit/dart/correction_producer.dart';
78
import 'package:analyzer/dart/ast/ast.dart';
89
import 'package:analyzer/dart/element/element.dart';
@@ -11,64 +12,110 @@ import 'package:analyzer_plugin/utilities/change_builder/change_builder_core.dar
1112
import 'package:analyzer_plugin/utilities/fixes/fixes.dart';
1213
import 'package:analyzer_plugin/utilities/range_factory.dart';
1314

14-
class CreateMixin extends ResolvedCorrectionProducer {
15-
String _mixinName = '';
16-
15+
class CreateMixin extends MultiCorrectionProducer {
1716
CreateMixin({required super.context});
1817

1918
@override
20-
CorrectionApplicability get applicability =>
21-
// TODO(applicability): comment on why.
22-
CorrectionApplicability.singleLocation;
23-
24-
@override
25-
List<String> get fixArguments => [_mixinName];
26-
27-
@override
28-
FixKind get fixKind => DartFixKind.CREATE_MIXIN;
29-
30-
@override
31-
Future<void> compute(ChangeBuilder builder) async {
19+
Future<List<ResolvedCorrectionProducer>> get producers async {
20+
String mixinName = '';
3221
Element? prefixElement;
22+
var withKeyword = false;
3323
var node = this.node;
3424
if (node is NamedType) {
3525
var importPrefix = node.importPrefix;
3626
if (importPrefix != null) {
3727
prefixElement = importPrefix.element2;
3828
if (prefixElement == null) {
39-
return;
29+
return const [];
4030
}
4131
}
42-
_mixinName = node.name.lexeme;
32+
withKeyword = node.parent is WithClause;
33+
mixinName = node.name.lexeme;
4334
} else if (node is SimpleIdentifier) {
4435
var parent = node.parent;
4536
switch (parent) {
46-
case PrefixedIdentifier():
47-
if (parent.identifier == node) {
48-
return;
49-
}
50-
case PropertyAccess():
51-
if (parent.propertyName == node) {
52-
return;
53-
}
54-
case ExpressionFunctionBody():
55-
if (parent.expression == node) {
56-
return;
37+
// Not the first identifier or the body of a function
38+
case PrefixedIdentifier(identifier: Expression invalid) ||
39+
PropertyAccess(propertyName: Expression invalid) ||
40+
ExpressionFunctionBody(expression: var invalid):
41+
if (invalid == node) {
42+
return const [];
5743
}
5844
}
59-
_mixinName = node.name;
45+
mixinName = node.name;
6046
} else if (node is PrefixedIdentifier) {
6147
if (node.parent is InstanceCreationExpression) {
62-
return;
48+
return const [];
6349
}
6450
prefixElement = node.prefix.element;
6551
if (prefixElement == null) {
66-
return;
52+
return const [];
6753
}
68-
_mixinName = node.identifier.name;
54+
mixinName = node.identifier.name;
6955
} else {
70-
return;
56+
return const [];
57+
}
58+
if (mixinName.isEmpty) {
59+
return const [];
7160
}
61+
return [
62+
// Lowercase mixin names are valid but not idiomatic so lower the
63+
// priority.
64+
if (mixinName.firstLetterIsLowercase)
65+
_CreateMixin.lowercase(
66+
mixinName,
67+
prefixElement,
68+
withKeyword: withKeyword,
69+
context: context,
70+
)
71+
else
72+
_CreateMixin.uppercase(
73+
mixinName,
74+
prefixElement,
75+
withKeyword: withKeyword,
76+
context: context,
77+
),
78+
];
79+
}
80+
}
81+
82+
class _CreateMixin extends ResolvedCorrectionProducer {
83+
final String _mixinName;
84+
final Element? prefixElement;
85+
86+
@override
87+
final FixKind fixKind;
88+
89+
_CreateMixin.lowercase(
90+
this._mixinName,
91+
this.prefixElement, {
92+
required bool withKeyword,
93+
required super.context,
94+
}) : fixKind =
95+
withKeyword
96+
? DartFixKind.CREATE_MIXIN_LOWERCASE_WITH
97+
: DartFixKind.CREATE_MIXIN_LOWERCASE;
98+
99+
_CreateMixin.uppercase(
100+
this._mixinName,
101+
this.prefixElement, {
102+
required bool withKeyword,
103+
required super.context,
104+
}) : fixKind =
105+
withKeyword
106+
? DartFixKind.CREATE_MIXIN_UPPERCASE_WITH
107+
: DartFixKind.CREATE_MIXIN_UPPERCASE;
108+
109+
@override
110+
CorrectionApplicability get applicability =>
111+
// TODO(applicability): comment on why.
112+
CorrectionApplicability.singleLocation;
113+
114+
@override
115+
List<String> get fixArguments => [_mixinName];
116+
117+
@override
118+
Future<void> compute(ChangeBuilder builder) async {
72119
// prepare environment
73120
LibraryFragment targetUnit;
74121
var prefix = '';

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

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -733,11 +733,21 @@ abstract final class DartFixKind {
733733
DartFixKindPriority.standard + 2,
734734
"Create class '{0}'",
735735
);
736+
static const CREATE_CLASS_UPPERCASE_WITH = FixKind(
737+
'dart.fix.create.class.uppercase.with',
738+
DartFixKindPriority.standard + 1,
739+
"Create class '{0}'",
740+
);
736741
static const CREATE_CLASS_LOWERCASE = FixKind(
737742
'dart.fix.create.class.lowercase',
738743
DartFixKindPriority.standard - 5,
739744
"Create class '{0}'",
740745
);
746+
static const CREATE_CLASS_LOWERCASE_WITH = FixKind(
747+
'dart.fix.create.class.lowercase.with',
748+
DartFixKindPriority.standard - 6,
749+
"Create class '{0}'",
750+
);
741751
static const CREATE_CONSTRUCTOR = FixKind(
742752
'dart.fix.create.constructor',
743753
DartFixKindPriority.standard,
@@ -820,11 +830,26 @@ abstract final class DartFixKind {
820830
DartFixKindPriority.standard + 1,
821831
'Create {0} missing override{1}',
822832
);
823-
static const CREATE_MIXIN = FixKind(
824-
'dart.fix.create.mixin',
833+
static const CREATE_MIXIN_UPPERCASE = FixKind(
834+
'dart.fix.create.mixin.uppercase',
825835
DartFixKindPriority.standard,
826836
"Create mixin '{0}'",
827837
);
838+
static const CREATE_MIXIN_UPPERCASE_WITH = FixKind(
839+
'dart.fix.create.mixin.uppercase.with',
840+
DartFixKindPriority.standard + 2,
841+
"Create mixin '{0}'",
842+
);
843+
static const CREATE_MIXIN_LOWERCASE = FixKind(
844+
'dart.fix.create.mixin.lowercase',
845+
DartFixKindPriority.standard - 6,
846+
"Create mixin '{0}'",
847+
);
848+
static const CREATE_MIXIN_LOWERCASE_WITH = FixKind(
849+
'dart.fix.create.mixin.lowercase.with',
850+
DartFixKindPriority.standard - 5,
851+
"Create mixin '{0}'",
852+
);
828853
static const CREATE_NO_SUCH_METHOD = FixKind(
829854
'dart.fix.create.noSuchMethod',
830855
DartFixKindPriority.standard - 1,

0 commit comments

Comments
 (0)