blob: 282bdddd5c5bccc4e260c5ba043a9b16aa77d6d5 [file] [log] [blame]
// Copyright (c) 2016, 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/element/element.dart';
import 'package:analyzer/src/dart/element/element.dart';
/// Keeps track of the set of non-synthetic child elements of an element,
/// yielding them one at a time in response to "get" method calls.
class ElementWalker {
/// The element whose child elements are being walked.
final Element element;
List<PropertyAccessorElement>? _accessors;
int _accessorIndex = 0;
List<ClassElement>? _classes;
int _classIndex = 0;
List<ConstructorElement>? _constructors;
int _constructorIndex = 0;
List<ClassElement>? _enums;
int _enumIndex = 0;
List<ExtensionElement>? _extensions;
int _extensionIndex = 0;
List<ExecutableElement>? _functions;
int _functionIndex = 0;
List<ClassElement>? _mixins;
int _mixinIndex = 0;
List<ParameterElement>? _parameters;
int _parameterIndex = 0;
List<TypeAliasElement>? _typedefs;
int _typedefIndex = 0;
List<TypeParameterElement>? _typeParameters;
int _typeParameterIndex = 0;
List<VariableElement>? _variables;
int _variableIndex = 0;
/// Creates an [ElementWalker] which walks the child elements of a class
/// element.
ElementWalker.forClass(ClassElement element)
: element = element,
_accessors = element.accessors.where(_isNotSynthetic).toList(),
_constructors = element.isMixinApplication
? null
: element.constructors.where(_isNotSynthetic).toList(),
_functions = element.methods,
_typeParameters = element.typeParameters,
_variables = element.fields.where(_isNotSynthetic).toList();
/// Creates an [ElementWalker] which walks the child elements of a compilation
/// unit element.
ElementWalker.forCompilationUnit(CompilationUnitElement element)
: element = element,
_accessors = element.accessors.where(_isNotSynthetic).toList(),
_classes = element.types,
_enums = element.enums,
_extensions = element.extensions,
_functions = element.functions,
_mixins = element.mixins,
_typedefs = element.typeAliases,
_variables = element.topLevelVariables.where(_isNotSynthetic).toList();
/// Creates an [ElementWalker] which walks the child elements of a compilation
/// unit element.
ElementWalker.forExecutable(ExecutableElement element)
: element = element,
_functions = const <ExecutableElement>[],
_parameters = element.parameters,
_typeParameters = element.typeParameters;
/// Creates an [ElementWalker] which walks the child elements of an extension
/// element.
ElementWalker.forExtension(ExtensionElement element)
: element = element,
_accessors = element.accessors.where(_isNotSynthetic).toList(),
_functions = element.methods,
_typeParameters = element.typeParameters,
_variables = element.fields.where(_isNotSynthetic).toList();
/// Creates an [ElementWalker] which walks the child elements of a typedef
/// element.
ElementWalker.forGenericFunctionType(GenericFunctionTypeElement element)
: element = element,
_parameters = element.parameters,
_typeParameters = element.typeParameters;
/// Creates an [ElementWalker] which walks the child elements of a typedef
/// element defined using a generic function type.
ElementWalker.forGenericTypeAlias(TypeAliasElement element)
: element = element,
_typeParameters = element.typeParameters;
/// Creates an [ElementWalker] which walks the child elements of a parameter
/// element.
ElementWalker.forParameter(ParameterElement element)
: element = element,
_parameters = element.parameters,
_typeParameters = element.typeParameters;
/// Creates an [ElementWalker] which walks the child elements of a typedef
/// element.
ElementWalker.forTypedef(TypeAliasElement element)
: element = element,
_parameters =
(element.aliasedElement as GenericFunctionTypeElement).parameters,
_typeParameters = element.typeParameters;
void consumeLocalElements() {
_functionIndex = _functions!.length;
}
void consumeParameters() {
_parameterIndex = _parameters!.length;
}
/// Returns the next non-synthetic child of [element] which is an accessor;
/// throws an [IndexError] if there are no more.
PropertyAccessorElementImpl getAccessor() =>
_accessors![_accessorIndex++] as PropertyAccessorElementImpl;
/// Returns the next non-synthetic child of [element] which is a class; throws
/// an [IndexError] if there are no more.
ClassElementImpl getClass() => _classes![_classIndex++] as ClassElementImpl;
/// Returns the next non-synthetic child of [element] which is a constructor;
/// throws an [IndexError] if there are no more.
ConstructorElementImpl getConstructor() =>
_constructors![_constructorIndex++] as ConstructorElementImpl;
/// Returns the next non-synthetic child of [element] which is an enum; throws
/// an [IndexError] if there are no more.
EnumElementImpl getEnum() => _enums![_enumIndex++] as EnumElementImpl;
ExtensionElement getExtension() => _extensions![_extensionIndex++];
/// Returns the next non-synthetic child of [element] which is a top level
/// function, method, or local function; throws an [IndexError] if there are
/// no more.
ExecutableElementImpl getFunction() =>
_functions![_functionIndex++] as ExecutableElementImpl;
/// Returns the next non-synthetic child of [element] which is a mixin; throws
/// an [IndexError] if there are no more.
ClassElement getMixin() => _mixins![_mixinIndex++];
/// Returns the next non-synthetic child of [element] which is a parameter;
/// throws an [IndexError] if there are no more.
ParameterElementImpl getParameter() =>
_parameters![_parameterIndex++] as ParameterElementImpl;
/// Returns the next non-synthetic child of [element] which is a typedef;
/// throws an [IndexError] if there are no more.
TypeAliasElementImpl getTypedef() =>
_typedefs![_typedefIndex++] as TypeAliasElementImpl;
/// Returns the next non-synthetic child of [element] which is a type
/// parameter; throws an [IndexError] if there are no more.
TypeParameterElementImpl getTypeParameter() =>
_typeParameters![_typeParameterIndex++] as TypeParameterElementImpl;
/// Returns the next non-synthetic child of [element] which is a top level
/// variable, field, or local variable; throws an [IndexError] if there are no
/// more.
VariableElementImpl getVariable() =>
_variables![_variableIndex++] as VariableElementImpl;
/// Verifies that all non-synthetic children of [element] have been obtained
/// from their corresponding "get" method calls; if not, throws a
/// [StateError].
void validate() {
void check(List<Element>? elements, int index) {
if (elements != null && elements.length != index) {
throw StateError(
'Unmatched ${elements[index].runtimeType} ${elements[index]}');
}
}
check(_accessors, _accessorIndex);
check(_classes, _classIndex);
check(_constructors, _constructorIndex);
check(_enums, _enumIndex);
check(_functions, _functionIndex);
check(_parameters, _parameterIndex);
check(_typedefs, _typedefIndex);
check(_typeParameters, _typeParameterIndex);
check(_variables, _variableIndex);
}
static bool _isNotSynthetic(Element e) => !e.isSynthetic;
}