mirror of
https://github.com/dart-lang/sdk
synced 2024-07-08 12:06:26 +00:00
analyzer: parse prefixed class constructor tearoff with no type args
Change-Id: I5f19dd9592f83820100e0ac498522245cac16dc4 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/212700 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com> Commit-Queue: Samuel Rawlins <srawlins@google.com>
This commit is contained in:
parent
2785fe9996
commit
e995cb5f7c
|
@ -266,21 +266,31 @@ class AstRewriter {
|
|||
return node;
|
||||
}
|
||||
var receiver = node.target!;
|
||||
if (receiver is! FunctionReference) {
|
||||
return node;
|
||||
}
|
||||
var propertyName = node.propertyName;
|
||||
if (propertyName.isSynthetic) {
|
||||
// This isn't a constructor reference.
|
||||
return node;
|
||||
}
|
||||
// A [ConstructorReference] with explicit type arguments is initially parsed
|
||||
// as a [PropertyAccess] with a [FunctionReference] target; for example:
|
||||
// `List<int>.filled` or `core.List<int>.filled`.
|
||||
var receiverIdentifier = receiver.function;
|
||||
if (receiverIdentifier is! Identifier) {
|
||||
// If [receiverIdentifier] is not an Identifier then [node] is not a
|
||||
// ConstructorReference.
|
||||
|
||||
Identifier receiverIdentifier;
|
||||
TypeArgumentList? typeArguments;
|
||||
if (receiver is PrefixedIdentifier) {
|
||||
receiverIdentifier = receiver;
|
||||
} else if (receiver is FunctionReference) {
|
||||
// A [ConstructorReference] with explicit type arguments is initially
|
||||
// parsed as a [PropertyAccess] with a [FunctionReference] target; for
|
||||
// example: `List<int>.filled` or `core.List<int>.filled`.
|
||||
var function = receiver.function;
|
||||
if (function is! Identifier) {
|
||||
// If [receiverIdentifier] is not an Identifier then [node] is not a
|
||||
// ConstructorReference.
|
||||
return node;
|
||||
}
|
||||
receiverIdentifier = function;
|
||||
typeArguments = receiver.typeArguments;
|
||||
} else {
|
||||
// If the receiver is not (initially) a prefixed identifier or a function
|
||||
// reference, then [node] is not a constructor reference.
|
||||
return node;
|
||||
}
|
||||
|
||||
|
@ -310,7 +320,7 @@ class AstRewriter {
|
|||
return _toConstructorReference_propertyAccess(
|
||||
node: node,
|
||||
receiver: receiverIdentifier,
|
||||
typeArguments: receiver.typeArguments!,
|
||||
typeArguments: typeArguments,
|
||||
classElement: element,
|
||||
);
|
||||
} else if (element is TypeAliasElement) {
|
||||
|
@ -323,7 +333,7 @@ class AstRewriter {
|
|||
return _toConstructorReference_propertyAccess(
|
||||
node: node,
|
||||
receiver: receiverIdentifier,
|
||||
typeArguments: receiver.typeArguments!,
|
||||
typeArguments: typeArguments,
|
||||
classElement: aliasedType.element,
|
||||
);
|
||||
}
|
||||
|
@ -393,12 +403,24 @@ class AstRewriter {
|
|||
return constructorReference;
|
||||
}
|
||||
|
||||
ConstructorReference _toConstructorReference_propertyAccess({
|
||||
AstNode _toConstructorReference_propertyAccess({
|
||||
required PropertyAccess node,
|
||||
required Identifier receiver,
|
||||
required TypeArgumentList typeArguments,
|
||||
required TypeArgumentList? typeArguments,
|
||||
required ClassElement classElement,
|
||||
}) {
|
||||
var name = node.propertyName.name;
|
||||
var constructorElement = name == 'new'
|
||||
? classElement.unnamedConstructor
|
||||
: classElement.getNamedConstructor(name);
|
||||
if (constructorElement == null && typeArguments == null) {
|
||||
// If there is no constructor by this name, and no type arguments,
|
||||
// do not rewrite the node. If there _are_ type arguments (like
|
||||
// `prefix.C<int>.name`, then it looks more like a constructor tearoff
|
||||
// than anything else, so continue with the rewrite.
|
||||
return node;
|
||||
}
|
||||
|
||||
var operator = node.operator;
|
||||
|
||||
var typeName = astFactory.typeName(receiver, typeArguments);
|
||||
|
|
|
@ -696,6 +696,108 @@ bar() {
|
|||
);
|
||||
}
|
||||
|
||||
test_prefixedAlias_nonGeneric_named() async {
|
||||
newFile('$testPackageLibPath/a.dart', content: '''
|
||||
class A {
|
||||
A.foo();
|
||||
}
|
||||
typedef TA = A;
|
||||
''');
|
||||
await assertNoErrorsInCode('''
|
||||
import 'a.dart' as a;
|
||||
bar() {
|
||||
a.TA.foo;
|
||||
}
|
||||
''');
|
||||
|
||||
var classElement =
|
||||
findElement.importFind('package:test/a.dart').class_('A');
|
||||
assertConstructorReference(
|
||||
findNode.constructorReference('a.TA.foo;'),
|
||||
classElement.getNamedConstructor('foo'),
|
||||
classElement,
|
||||
'A Function()',
|
||||
expectedPrefix: findElement.import('package:test/a.dart').prefix,
|
||||
expectedTypeNameElement:
|
||||
findElement.importFind('package:test/a.dart').typeAlias('TA'),
|
||||
);
|
||||
}
|
||||
|
||||
test_prefixedAlias_nonGeneric_unnamed() async {
|
||||
newFile('$testPackageLibPath/a.dart', content: '''
|
||||
class A {
|
||||
A();
|
||||
}
|
||||
typedef TA = A;
|
||||
''');
|
||||
await assertNoErrorsInCode('''
|
||||
import 'a.dart' as a;
|
||||
bar() {
|
||||
a.TA.new;
|
||||
}
|
||||
''');
|
||||
|
||||
var classElement =
|
||||
findElement.importFind('package:test/a.dart').class_('A');
|
||||
assertConstructorReference(
|
||||
findNode.constructorReference('a.TA.new;'),
|
||||
classElement.unnamedConstructor,
|
||||
classElement,
|
||||
'A Function()',
|
||||
expectedPrefix: findElement.import('package:test/a.dart').prefix,
|
||||
expectedTypeNameElement:
|
||||
findElement.importFind('package:test/a.dart').typeAlias('TA'),
|
||||
);
|
||||
}
|
||||
|
||||
test_prefixedClass_nonGeneric_named() async {
|
||||
newFile('$testPackageLibPath/a.dart', content: '''
|
||||
class A {
|
||||
A.foo();
|
||||
}
|
||||
''');
|
||||
await assertNoErrorsInCode('''
|
||||
import 'a.dart' as a;
|
||||
bar() {
|
||||
a.A.foo;
|
||||
}
|
||||
''');
|
||||
|
||||
var classElement =
|
||||
findElement.importFind('package:test/a.dart').class_('A');
|
||||
assertConstructorReference(
|
||||
findNode.constructorReference('a.A.foo;'),
|
||||
classElement.getNamedConstructor('foo'),
|
||||
classElement,
|
||||
'A Function()',
|
||||
expectedPrefix: findElement.import('package:test/a.dart').prefix,
|
||||
);
|
||||
}
|
||||
|
||||
test_prefixedClass_nonGeneric_unnamed() async {
|
||||
newFile('$testPackageLibPath/a.dart', content: '''
|
||||
class A {
|
||||
A();
|
||||
}
|
||||
''');
|
||||
await assertNoErrorsInCode('''
|
||||
import 'a.dart' as a;
|
||||
bar() {
|
||||
a.A.new;
|
||||
}
|
||||
''');
|
||||
|
||||
var classElement =
|
||||
findElement.importFind('package:test/a.dart').class_('A');
|
||||
assertConstructorReference(
|
||||
findNode.constructorReference('a.A.new;'),
|
||||
classElement.unnamedConstructor,
|
||||
classElement,
|
||||
'A Function()',
|
||||
expectedPrefix: findElement.import('package:test/a.dart').prefix,
|
||||
);
|
||||
}
|
||||
|
||||
test_typeAlias_generic_const() async {
|
||||
await assertNoErrorsInCode('''
|
||||
class A<T> {
|
||||
|
|
Loading…
Reference in New Issue
Block a user