blob: 8cdade2f794b1407d46ba86694b0ab0b8b6b4fd9 [file] [log] [blame]
// Copyright (c) 2014, 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/analysis/features.dart';
import 'package:analyzer/dart/ast/ast.dart';
import 'package:analyzer/dart/ast/token.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/nullability_suffix.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/analysis/session.dart';
import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/dart/element/type.dart';
import 'package:analyzer/src/dart/resolver/variance.dart';
import 'package:analyzer/src/generated/engine.dart';
import 'package:analyzer/src/generated/source.dart';
import 'package:analyzer/src/generated/testing/ast_test_factory.dart';
import 'package:analyzer/src/generated/utilities_dart.dart';
import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
import 'package:path/path.dart';
/// The class `ElementFactory` defines utility methods used to create elements
/// for testing purposes. The elements that are created are complete in the
/// sense that as much of the element model as can be created, given the
/// provided information, has been created.
@internal
class ElementFactory {
/// The element representing the class 'Object'.
static ClassElementImpl? _objectElement;
static InterfaceType? _objectType;
static ClassElementImpl get object {
return _objectElement ??= classElement("Object", null);
}
static InterfaceType get objectType {
return _objectType ??= object.instantiate(
typeArguments: const [],
nullabilitySuffix: NullabilitySuffix.star,
);
}
static ClassElementImpl classElement(
String typeName, InterfaceType? superclassType,
[List<String>? parameterNames]) {
ClassElementImpl element = ClassElementImpl(typeName, 0);
element.constructors = const <ConstructorElement>[];
element.supertype = superclassType;
if (parameterNames != null) {
element.typeParameters = typeParameters(parameterNames);
}
return element;
}
static ClassElementImpl classElement2(String typeName,
[List<String>? parameterNames]) =>
classElement(typeName, objectType, parameterNames);
static ClassElementImpl classElement3({
required String name,
List<TypeParameterElement>? typeParameters,
List<String> typeParameterNames = const [],
InterfaceType? supertype,
List<InterfaceType> mixins = const [],
List<InterfaceType> interfaces = const [],
}) {
typeParameters ??= ElementFactory.typeParameters(typeParameterNames);
supertype ??= objectType;
var element = ClassElementImpl(name, 0);
element.typeParameters = typeParameters;
element.supertype = supertype;
element.mixins = mixins;
element.interfaces = interfaces;
element.constructors = const <ConstructorElement>[];
return element;
}
static ClassElementImpl classTypeAlias(
String typeName, InterfaceType superclassType,
[List<String>? parameterNames]) {
ClassElementImpl element =
classElement(typeName, superclassType, parameterNames);
element.isMixinApplication = true;
return element;
}
static ClassElementImpl classTypeAlias2(String typeName,
[List<String>? parameterNames]) =>
classTypeAlias(typeName, objectType, parameterNames);
static CompilationUnitElementImpl compilationUnit({
required Source source,
Source? librarySource,
LineInfo? lineInfo,
}) {
return CompilationUnitElementImpl(
source: source,
librarySource: librarySource ?? source,
lineInfo: lineInfo ?? LineInfo([0]),
);
}
static ConstLocalVariableElementImpl constLocalVariableElement(String name) =>
ConstLocalVariableElementImpl(name, 0);
static ConstructorElementImpl constructorElement(
ClassElement definingClass, String? name, bool isConst,
[List<DartType> argumentTypes = const []]) {
var offset = name == null ? -1 : 0;
// A constructor declared as `C.new` is unnamed, and is modeled as such.
var constructor = name == null || name == 'new'
? ConstructorElementImpl('', offset)
: ConstructorElementImpl(name, offset);
if (name != null) {
if (name.isEmpty) {
constructor.nameEnd = definingClass.name.length;
} else {
constructor.periodOffset = definingClass.name.length;
constructor.nameEnd = definingClass.name.length + name.length + 1;
}
}
constructor.isSynthetic = name == null;
constructor.isConst = isConst;
constructor.parameters = _requiredParameters(argumentTypes);
constructor.enclosingElement = definingClass;
if (!constructor.isSynthetic) {
constructor.constantInitializers = <ConstructorInitializer>[];
}
return constructor;
}
static ConstructorElementImpl constructorElement2(
ClassElement definingClass, String? name,
[List<DartType> argumentTypes = const []]) =>
constructorElement(definingClass, name, false, argumentTypes);
static FieldElementImpl fieldElement(
String name, bool isStatic, bool isFinal, bool isConst, DartType type,
{Expression? initializer}) {
FieldElementImpl field =
isConst ? ConstFieldElementImpl(name, 0) : FieldElementImpl(name, 0);
field.isConst = isConst;
field.isFinal = isFinal;
field.isStatic = isStatic;
field.type = type;
if (isConst) {
(field as ConstFieldElementImpl).constantInitializer = initializer;
}
PropertyAccessorElementImpl_ImplicitGetter(field);
if (!isConst && !isFinal) {
PropertyAccessorElementImpl_ImplicitSetter(field);
}
return field;
}
static FieldFormalParameterElementImpl fieldFormalParameter(
Identifier name) =>
FieldFormalParameterElementImpl(
name: name.name,
nameOffset: name.offset,
parameterKind: ParameterKind.REQUIRED,
);
/// Destroy any static state retained by [ElementFactory]. This should be
/// called from the `setUp` method of any tests that use [ElementFactory], in
/// order to ensure that state is not shared between multiple tests.
static void flushStaticState() {
_objectElement = null;
}
static PropertyAccessorElementImpl getterElement(
String name, bool isStatic, DartType type) {
FieldElementImpl field = FieldElementImpl(name, -1);
field.isStatic = isStatic;
field.isSynthetic = true;
field.type = type;
field.isFinal = true;
PropertyAccessorElementImpl getter = PropertyAccessorElementImpl(name, 0);
getter.isSynthetic = false;
getter.isGetter = true;
getter.variable = field;
getter.returnType = type;
getter.isStatic = isStatic;
field.getter = getter;
return getter;
}
static LibraryElementImpl library(
AnalysisContext context, String libraryName) {
String fileName = "/$libraryName.dart";
CompilationUnitElementImpl unit = compilationUnit(
source: NonExistingSource(fileName, toUri(fileName)),
);
LibraryElementImpl library = LibraryElementImpl(
context,
_MockAnalysisSession(),
libraryName,
0,
libraryName.length,
FeatureSet.latestLanguageVersion(),
);
library.definingCompilationUnit = unit;
return library;
}
static LocalVariableElementImpl localVariableElement(Identifier name) =>
LocalVariableElementImpl(name.name, name.offset);
static LocalVariableElementImpl localVariableElement2(String name) =>
LocalVariableElementImpl(name, 0);
static MethodElementImpl methodElement(String methodName, DartType returnType,
[List<DartType> argumentTypes = const []]) {
MethodElementImpl method = MethodElementImpl(methodName, 0);
method.parameters = _requiredParameters(argumentTypes);
method.returnType = returnType;
return method;
}
static MethodElementImpl methodElementWithParameters(
ClassElement enclosingElement,
String methodName,
DartType returnType,
List<ParameterElement> parameters) {
MethodElementImpl method = MethodElementImpl(methodName, 0);
method.enclosingElement = enclosingElement;
method.parameters = parameters;
method.returnType = returnType;
return method;
}
static MixinElementImpl mixinElement({
required String name,
List<TypeParameterElement>? typeParameters,
List<String> typeParameterNames = const [],
List<InterfaceType> constraints = const [],
List<InterfaceType> interfaces = const [],
}) {
typeParameters ??= ElementFactory.typeParameters(typeParameterNames);
if (constraints.isEmpty) {
constraints = [objectType];
}
var element = MixinElementImpl(name, 0);
element.typeParameters = typeParameters;
element.superclassConstraints = constraints;
element.interfaces = interfaces;
element.constructors = const <ConstructorElement>[];
return element;
}
static ParameterElementImpl namedParameter(String name) {
return ParameterElementImpl(
name: name,
nameOffset: 0,
parameterKind: ParameterKind.NAMED,
);
}
static ParameterElementImpl namedParameter2(String name, DartType type) {
var parameter = ParameterElementImpl(
name: name,
nameOffset: 0,
parameterKind: ParameterKind.NAMED,
);
parameter.type = type;
return parameter;
}
static ParameterElementImpl positionalParameter(String name) {
return ParameterElementImpl(
name: name,
nameOffset: 0,
parameterKind: ParameterKind.POSITIONAL,
);
}
static ParameterElementImpl positionalParameter2(String name, DartType type) {
var parameter = ParameterElementImpl(
name: name,
nameOffset: 0,
parameterKind: ParameterKind.POSITIONAL,
);
parameter.type = type;
return parameter;
}
static PrefixElementImpl prefix(String name) => PrefixElementImpl(name, 0);
static ParameterElementImpl requiredParameter(String name) {
return ParameterElementImpl(
name: name,
nameOffset: 0,
parameterKind: ParameterKind.REQUIRED,
);
}
static ParameterElementImpl requiredParameter2(String name, DartType type) {
var parameter = ParameterElementImpl(
name: name,
nameOffset: 0,
parameterKind: ParameterKind.REQUIRED,
);
parameter.type = type;
return parameter;
}
static PropertyAccessorElementImpl setterElement(
String name, bool isStatic, DartType type) {
FieldElementImpl field = FieldElementImpl(name, -1);
field.isStatic = isStatic;
field.isSynthetic = true;
field.type = type;
PropertyAccessorElementImpl getter = PropertyAccessorElementImpl(name, -1);
getter.isGetter = true;
getter.variable = field;
getter.returnType = type;
field.getter = getter;
ParameterElementImpl parameter = requiredParameter2("a", type);
PropertyAccessorElementImpl setter = PropertyAccessorElementImpl(name, -1);
setter.isSetter = true;
setter.isSynthetic = true;
setter.variable = field;
setter.parameters = <ParameterElement>[parameter];
setter.returnType = VoidTypeImpl.instance;
setter.isStatic = isStatic;
field.setter = setter;
return setter;
}
static TopLevelVariableElementImpl topLevelVariableElement(Identifier name) =>
TopLevelVariableElementImpl(name.name, name.offset);
static TopLevelVariableElementImpl topLevelVariableElement2(String name) =>
topLevelVariableElement3(name, false, false, DynamicTypeImpl.instance);
static TopLevelVariableElementImpl topLevelVariableElement3(
String name, bool isConst, bool isFinal, DartType type) {
TopLevelVariableElementImpl variable;
if (isConst) {
ConstTopLevelVariableElementImpl constant =
ConstTopLevelVariableElementImpl(name, -1);
var typeElement = type.element as ClassElement;
var initializer = AstTestFactory.instanceCreationExpression2(
Keyword.CONST, AstTestFactory.namedType(typeElement));
if (type is InterfaceType) {
var element = typeElement.unnamedConstructor;
initializer.constructorName.staticElement = element;
}
constant.constantInitializer = initializer;
variable = constant;
} else {
variable = TopLevelVariableElementImpl(name, -1);
}
variable.isConst = isConst;
variable.isFinal = isFinal;
variable.isSynthetic = false;
variable.type = type;
PropertyAccessorElementImpl_ImplicitGetter(variable);
if (!isConst && !isFinal) {
PropertyAccessorElementImpl_ImplicitSetter(variable);
}
return variable;
}
static TypeParameterElementImpl typeParameterElement(String name) {
return TypeParameterElementImpl(name, 0);
}
static List<TypeParameterElement> typeParameters(List<String> names) {
return names.map((name) => typeParameterWithType(name)).toList();
}
static TypeParameterElementImpl typeParameterWithType(String name,
[DartType? bound, Variance? variance]) {
TypeParameterElementImpl typeParameter = typeParameterElement(name);
typeParameter.bound = bound;
typeParameter.variance = variance;
return typeParameter;
}
static List<ParameterElementImpl> _requiredParameters(
List<DartType> argumentTypes) {
var parameters = argumentTypes.mapIndexed((index, type) {
var parameter = ParameterElementImpl(
name: 'a$index',
nameOffset: index,
parameterKind: ParameterKind.REQUIRED,
);
parameter.type = type;
return parameter;
}).toList();
return parameters;
}
}
class _MockAnalysisSession implements AnalysisSessionImpl {
@override
dynamic noSuchMethod(Invocation invocation) => super.noSuchMethod(invocation);
}