mirror of
https://github.com/dart-lang/sdk
synced 2024-09-05 08:24:39 +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;
|
return node;
|
||||||
}
|
}
|
||||||
var receiver = node.target!;
|
var receiver = node.target!;
|
||||||
if (receiver is! FunctionReference) {
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
var propertyName = node.propertyName;
|
var propertyName = node.propertyName;
|
||||||
if (propertyName.isSynthetic) {
|
if (propertyName.isSynthetic) {
|
||||||
// This isn't a constructor reference.
|
// This isn't a constructor reference.
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
// A [ConstructorReference] with explicit type arguments is initially parsed
|
|
||||||
// as a [PropertyAccess] with a [FunctionReference] target; for example:
|
Identifier receiverIdentifier;
|
||||||
// `List<int>.filled` or `core.List<int>.filled`.
|
TypeArgumentList? typeArguments;
|
||||||
var receiverIdentifier = receiver.function;
|
if (receiver is PrefixedIdentifier) {
|
||||||
if (receiverIdentifier is! Identifier) {
|
receiverIdentifier = receiver;
|
||||||
// If [receiverIdentifier] is not an Identifier then [node] is not a
|
} else if (receiver is FunctionReference) {
|
||||||
// ConstructorReference.
|
// 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;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -310,7 +320,7 @@ class AstRewriter {
|
||||||
return _toConstructorReference_propertyAccess(
|
return _toConstructorReference_propertyAccess(
|
||||||
node: node,
|
node: node,
|
||||||
receiver: receiverIdentifier,
|
receiver: receiverIdentifier,
|
||||||
typeArguments: receiver.typeArguments!,
|
typeArguments: typeArguments,
|
||||||
classElement: element,
|
classElement: element,
|
||||||
);
|
);
|
||||||
} else if (element is TypeAliasElement) {
|
} else if (element is TypeAliasElement) {
|
||||||
|
@ -323,7 +333,7 @@ class AstRewriter {
|
||||||
return _toConstructorReference_propertyAccess(
|
return _toConstructorReference_propertyAccess(
|
||||||
node: node,
|
node: node,
|
||||||
receiver: receiverIdentifier,
|
receiver: receiverIdentifier,
|
||||||
typeArguments: receiver.typeArguments!,
|
typeArguments: typeArguments,
|
||||||
classElement: aliasedType.element,
|
classElement: aliasedType.element,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -393,12 +403,24 @@ class AstRewriter {
|
||||||
return constructorReference;
|
return constructorReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
ConstructorReference _toConstructorReference_propertyAccess({
|
AstNode _toConstructorReference_propertyAccess({
|
||||||
required PropertyAccess node,
|
required PropertyAccess node,
|
||||||
required Identifier receiver,
|
required Identifier receiver,
|
||||||
required TypeArgumentList typeArguments,
|
required TypeArgumentList? typeArguments,
|
||||||
required ClassElement classElement,
|
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 operator = node.operator;
|
||||||
|
|
||||||
var typeName = astFactory.typeName(receiver, typeArguments);
|
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 {
|
test_typeAlias_generic_const() async {
|
||||||
await assertNoErrorsInCode('''
|
await assertNoErrorsInCode('''
|
||||||
class A<T> {
|
class A<T> {
|
||||||
|
|
Loading…
Reference in a new issue