mirror of
https://github.com/dart-lang/sdk
synced 2024-10-14 11:58:13 +00:00
[CMSR] Improve 'get invocation' implementation.
Change-Id: I871eddc1727ea6a51e169f4031d55ba3bc93527d Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/310860 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
f264102869
commit
a8a3f3f77e
|
@ -895,7 +895,7 @@ class _SignatureUpdater {
|
|||
}
|
||||
|
||||
ArgumentList argumentList;
|
||||
final invocation = selection.coveringNode.invocation;
|
||||
final invocation = selection.invocation;
|
||||
switch (invocation) {
|
||||
case ConstructorDeclaration constructor:
|
||||
return ChangeStatusFailureSuperFormalParameter(
|
||||
|
@ -905,6 +905,8 @@ class _SignatureUpdater {
|
|||
argumentList = instanceCreation.argumentList;
|
||||
case MethodInvocation invocation:
|
||||
argumentList = invocation.argumentList;
|
||||
case RedirectingConstructorInvocation invocation:
|
||||
argumentList = invocation.argumentList;
|
||||
case SuperConstructorInvocation invocation:
|
||||
argumentList = invocation.argumentList;
|
||||
default:
|
||||
|
@ -1027,15 +1029,7 @@ class _SignatureUpdater {
|
|||
}
|
||||
}
|
||||
|
||||
extension on FormalParameterList {
|
||||
bool get hasTrailingComma {
|
||||
final last = parameters.lastOrNull;
|
||||
final nextToken = last?.endToken.next;
|
||||
return nextToken != null && nextToken.type == TokenType.COMMA;
|
||||
}
|
||||
}
|
||||
|
||||
extension on AstNode {
|
||||
extension _AstNodeExtension on AstNode {
|
||||
AstNode? get declaration {
|
||||
final self = this;
|
||||
if (self is FunctionExpression) {
|
||||
|
@ -1076,27 +1070,49 @@ extension on AstNode {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
extension _FormalParameterListExtension on FormalParameterList {
|
||||
bool get hasTrailingComma {
|
||||
final last = parameters.lastOrNull;
|
||||
final nextToken = last?.endToken.next;
|
||||
return nextToken != null && nextToken.type == TokenType.COMMA;
|
||||
}
|
||||
}
|
||||
|
||||
extension _SelectionExtension on Selection {
|
||||
AstNode? get invocation {
|
||||
AstNode? self = this;
|
||||
if (self is ArgumentList) {
|
||||
self = self.parent;
|
||||
} else if (self is NamedType && self.parent is ConstructorName) {
|
||||
self = self.parent?.parent;
|
||||
final node = coveringNode;
|
||||
switch (node) {
|
||||
case RedirectingConstructorInvocation():
|
||||
case SuperConstructorInvocation():
|
||||
return node;
|
||||
}
|
||||
switch (self) {
|
||||
case SimpleIdentifier():
|
||||
final parent = self.parent;
|
||||
if (parent is ConstructorDeclaration) {
|
||||
return parent;
|
||||
} else if (parent is MethodInvocation) {
|
||||
|
||||
final parent = node.parent;
|
||||
switch (parent) {
|
||||
case MethodInvocation():
|
||||
if (isCoveredByNode(parent.methodName)) {
|
||||
return parent;
|
||||
}
|
||||
case RedirectingConstructorInvocation():
|
||||
if (isCoveredByToken(parent.thisKeyword)) {
|
||||
return parent;
|
||||
}
|
||||
case InstanceCreationExpression():
|
||||
case MethodInvocation():
|
||||
case SuperConstructorInvocation():
|
||||
return self;
|
||||
if (isCoveredByToken(parent.superKeyword)) {
|
||||
return parent;
|
||||
}
|
||||
}
|
||||
|
||||
final parent2 = parent?.parent;
|
||||
switch (parent2) {
|
||||
case InstanceCreationExpression():
|
||||
if (isCoveredByNode(parent2.constructorName)) {
|
||||
return parent2;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// BSD-style license that can be found in the LICENSE file.
|
||||
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/dart/ast/token.dart';
|
||||
import 'package:analyzer/dart/ast/visitor.dart';
|
||||
import 'package:analyzer/source/source_range.dart';
|
||||
import 'package:analyzer/src/utilities/extensions/ast.dart';
|
||||
|
@ -25,6 +26,14 @@ class Selection {
|
|||
Selection(
|
||||
{required this.offset, required this.length, required this.coveringNode});
|
||||
|
||||
bool isCoveredByNode(AstNode node) {
|
||||
return node.offset <= offset && offset + length <= node.end;
|
||||
}
|
||||
|
||||
bool isCoveredByToken(Token token) {
|
||||
return token.offset <= offset && offset + length <= token.end;
|
||||
}
|
||||
|
||||
/// Returns the contiguous subset of [coveringNode] children that are at
|
||||
/// least partially covered by the selection. Touching is not enough.
|
||||
///
|
||||
|
|
|
@ -944,6 +944,68 @@ void f() {
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void>
|
||||
test_classConstructor_redirectingConstructorInvocation_named() async {
|
||||
await _analyzeValidSelection(r'''
|
||||
class A {
|
||||
final int a;
|
||||
^A.named(int a);
|
||||
A() : this.named(0);
|
||||
}
|
||||
''');
|
||||
|
||||
final signatureUpdate = MethodSignatureUpdate(
|
||||
formalParameters: [
|
||||
FormalParameterUpdate(
|
||||
id: 0,
|
||||
kind: FormalParameterKind.requiredNamed,
|
||||
),
|
||||
],
|
||||
formalParametersTrailingComma: TrailingComma.ifPresent,
|
||||
argumentsTrailingComma: ArgumentsTrailingComma.ifPresent,
|
||||
);
|
||||
|
||||
await _assertUpdate(signatureUpdate, r'''
|
||||
>>>>>>> /home/test/lib/test.dart
|
||||
class A {
|
||||
final int a;
|
||||
A.named({required int a});
|
||||
A() : this.named(a: 0);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void>
|
||||
test_classConstructor_redirectingConstructorInvocation_unnamed() async {
|
||||
await _analyzeValidSelection(r'''
|
||||
class A {
|
||||
final int a;
|
||||
^A(int a);
|
||||
A.named() : this(0);
|
||||
}
|
||||
''');
|
||||
|
||||
final signatureUpdate = MethodSignatureUpdate(
|
||||
formalParameters: [
|
||||
FormalParameterUpdate(
|
||||
id: 0,
|
||||
kind: FormalParameterKind.requiredNamed,
|
||||
),
|
||||
],
|
||||
formalParametersTrailingComma: TrailingComma.ifPresent,
|
||||
argumentsTrailingComma: ArgumentsTrailingComma.ifPresent,
|
||||
);
|
||||
|
||||
await _assertUpdate(signatureUpdate, r'''
|
||||
>>>>>>> /home/test/lib/test.dart
|
||||
class A {
|
||||
final int a;
|
||||
A({required int a});
|
||||
A.named() : this(a: 0);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_classConstructor_requiredNamed_reorder() async {
|
||||
await _analyzeValidSelection(r'''
|
||||
class A {
|
||||
|
@ -1158,6 +1220,79 @@ void f() {
|
|||
''');
|
||||
}
|
||||
|
||||
Future<void> test_classConstructor_superConstructorInvocation_named() async {
|
||||
await _analyzeValidSelection(r'''
|
||||
class A {
|
||||
final int a;
|
||||
^A.named(int a);
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
B() : super.named(0);
|
||||
}
|
||||
''');
|
||||
|
||||
final signatureUpdate = MethodSignatureUpdate(
|
||||
formalParameters: [
|
||||
FormalParameterUpdate(
|
||||
id: 0,
|
||||
kind: FormalParameterKind.requiredNamed,
|
||||
),
|
||||
],
|
||||
formalParametersTrailingComma: TrailingComma.ifPresent,
|
||||
argumentsTrailingComma: ArgumentsTrailingComma.ifPresent,
|
||||
);
|
||||
|
||||
await _assertUpdate(signatureUpdate, r'''
|
||||
>>>>>>> /home/test/lib/test.dart
|
||||
class A {
|
||||
final int a;
|
||||
A.named({required int a});
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
B() : super.named(a: 0);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void>
|
||||
test_classConstructor_superConstructorInvocation_unnamed() async {
|
||||
await _analyzeValidSelection(r'''
|
||||
class A {
|
||||
final int a;
|
||||
^A(int a);
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
B() : super(0);
|
||||
}
|
||||
''');
|
||||
|
||||
final signatureUpdate = MethodSignatureUpdate(
|
||||
formalParameters: [
|
||||
FormalParameterUpdate(
|
||||
id: 0,
|
||||
kind: FormalParameterKind.requiredNamed,
|
||||
),
|
||||
],
|
||||
formalParametersTrailingComma: TrailingComma.ifPresent,
|
||||
argumentsTrailingComma: ArgumentsTrailingComma.ifPresent,
|
||||
);
|
||||
|
||||
await _assertUpdate(signatureUpdate, r'''
|
||||
>>>>>>> /home/test/lib/test.dart
|
||||
class A {
|
||||
final int a;
|
||||
A({required int a});
|
||||
}
|
||||
|
||||
class B extends A {
|
||||
B() : super(a: 0);
|
||||
}
|
||||
''');
|
||||
}
|
||||
|
||||
Future<void> test_classMethod_optionalNamed_reorder_less() async {
|
||||
await _analyzeValidSelection(r'''
|
||||
class A {
|
||||
|
|
|
@ -198,6 +198,12 @@ class RangeFactory {
|
|||
return SourceRange(startOffset, length);
|
||||
}
|
||||
|
||||
/// Return a source range that starts at the given [startOffset], and has
|
||||
/// the given [length].
|
||||
SourceRange startOffsetLength(int startOffset, int length) {
|
||||
return SourceRange(startOffset, length);
|
||||
}
|
||||
|
||||
/// Return a source range that starts at the start of [leftEntity] and ends at
|
||||
/// the start of [rightEntity].
|
||||
SourceRange startStart(
|
||||
|
|
Loading…
Reference in a new issue