blob: 9daaea25cc74aa1026198121fd7daf071b2d36b8 [file] [log] [blame]
// Copyright (c) 2019, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/standard_ast_factory.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/scope.dart';
import 'package:analyzer/error/listener.dart';
import 'package:analyzer/src/dart/ast/utilities.dart';
import 'package:analyzer/src/error/codes.dart';
/// Helper for [MethodInvocation]s into [InstanceCreationExpression] to support
/// the optional `new` and `const` feature, or [ExtensionOverride].
class AstRewriter {
final ErrorReporter _errorReporter;
AstRewriter(this._errorReporter);
AstNode methodInvocation(Scope nameScope, MethodInvocation node) {
SimpleIdentifier methodName = node.methodName;
if (methodName.isSynthetic) {
// This isn't a constructor invocation because the method name is
// synthetic.
return node;
}
Expression target = node.target;
if (target == null) {
// Possible cases: C() or C<>()
if (node.realTarget != null) {
// This isn't a constructor invocation because it's in a cascade.
return node;
}
Element element = nameScope.lookup(methodName.name).getter;
if (element is ClassElement) {
TypeName typeName = astFactory.typeName(methodName, node.typeArguments);
ConstructorName constructorName =
astFactory.constructorName(typeName, null, null);
InstanceCreationExpression instanceCreationExpression =
astFactory.instanceCreationExpression(
null, constructorName, node.argumentList);
NodeReplacer.replace(node, instanceCreationExpression);
return instanceCreationExpression;
} else if (element is ExtensionElement) {
ExtensionOverride extensionOverride = astFactory.extensionOverride(
extensionName: methodName,
typeArguments: node.typeArguments,
argumentList: node.argumentList);
NodeReplacer.replace(node, extensionOverride);
return extensionOverride;
}
} else if (target is SimpleIdentifier) {
// Possible cases: C.n(), p.C() or p.C<>()
if (node.isNullAware) {
// This isn't a constructor invocation because a null aware operator is
// being used.
}
Element element = nameScope.lookup(target.name).getter;
if (element is ClassElement) {
// Possible case: C.n()
var constructorElement = element.getNamedConstructor(methodName.name);
if (constructorElement != null) {
var typeArguments = node.typeArguments;
if (typeArguments != null) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR,
typeArguments,
[element.name, constructorElement.name]);
}
TypeName typeName = astFactory.typeName(target, null);
ConstructorName constructorName =
astFactory.constructorName(typeName, node.operator, methodName);
// TODO(scheglov) I think we should drop "typeArguments" below.
InstanceCreationExpression instanceCreationExpression =
astFactory.instanceCreationExpression(
null, constructorName, node.argumentList,
typeArguments: typeArguments);
NodeReplacer.replace(node, instanceCreationExpression);
return instanceCreationExpression;
}
} else if (element is PrefixElement) {
// Possible cases: p.C() or p.C<>()
Element prefixedElement = element.scope.lookup(methodName.name).getter;
if (prefixedElement is ClassElement) {
TypeName typeName = astFactory.typeName(
astFactory.prefixedIdentifier(target, node.operator, methodName),
node.typeArguments);
ConstructorName constructorName =
astFactory.constructorName(typeName, null, null);
InstanceCreationExpression instanceCreationExpression =
astFactory.instanceCreationExpression(
null, constructorName, node.argumentList);
NodeReplacer.replace(node, instanceCreationExpression);
return instanceCreationExpression;
} else if (prefixedElement is ExtensionElement) {
PrefixedIdentifier extensionName =
astFactory.prefixedIdentifier(target, node.operator, methodName);
ExtensionOverride extensionOverride = astFactory.extensionOverride(
extensionName: extensionName,
typeArguments: node.typeArguments,
argumentList: node.argumentList);
NodeReplacer.replace(node, extensionOverride);
return extensionOverride;
}
}
} else if (target is PrefixedIdentifier) {
// Possible case: p.C.n()
Element prefixElement = nameScope.lookup(target.prefix.name).getter;
target.prefix.staticElement = prefixElement;
if (prefixElement is PrefixElement) {
Element element =
prefixElement.scope.lookup(target.identifier.name).getter;
if (element is ClassElement) {
var constructorElement = element.getNamedConstructor(methodName.name);
if (constructorElement != null) {
var typeArguments = node.typeArguments;
if (typeArguments != null) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode
.WRONG_NUMBER_OF_TYPE_ARGUMENTS_CONSTRUCTOR,
typeArguments,
[element.name, constructorElement.name]);
}
TypeName typeName = astFactory.typeName(target, typeArguments);
ConstructorName constructorName =
astFactory.constructorName(typeName, node.operator, methodName);
InstanceCreationExpression instanceCreationExpression =
astFactory.instanceCreationExpression(
null, constructorName, node.argumentList);
NodeReplacer.replace(node, instanceCreationExpression);
return instanceCreationExpression;
}
}
}
}
return node;
}
}