blob: b44613cb38cd755f08627c56037dbc18d097cd1f [file] [log] [blame]
// Copyright (c) 2018, 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/element/element.dart';
import 'package:analyzer/src/test_utilities/function_ast_visitor.dart';
/// Helper for finding elements declared in the resolved [unit].
class FindElement extends _FindElementBase {
final CompilationUnit unit;
FindElement(this.unit);
@override
CompilationUnitElement get unitElement => unit.declaredElement!;
ExportElement export(String targetUri) {
ExportElement? result;
for (var export in unitElement.library.exports) {
var exportedUri = export.exportedLibrary!.source.uri.toString();
if (exportedUri == targetUri) {
if (result != null) {
throw StateError('Not unique: $targetUri');
}
result = export;
}
}
if (result != null) {
return result;
}
throw StateError('Not found: $targetUri');
}
FieldFormalParameterElement fieldFormalParameter(String name) {
return parameter(name) as FieldFormalParameterElement;
}
FunctionElement function(String name) {
for (var function in unitElement.functions) {
if (function.name == name) {
return function;
}
}
throw StateError('Not found: $name');
}
ImportElement import(String targetUri, {bool mustBeUnique = true}) {
ImportElement? importElement;
for (var import in unitElement.library.imports) {
var importedUri = import.importedLibrary!.source.uri.toString();
if (importedUri == targetUri) {
if (importElement == null) {
importElement = import;
} else if (mustBeUnique) {
throw StateError('Not unique: $targetUri');
}
}
}
if (importElement != null) {
return importElement;
}
throw StateError('Not found: $targetUri');
}
ImportFindElement importFind(String targetUri, {bool mustBeUnique = true}) {
var import = this.import(targetUri, mustBeUnique: mustBeUnique);
return ImportFindElement(import);
}
LabelElement label(String name) {
LabelElement? result;
void updateResult(Element element) {
if (element is LabelElement && element.name == name) {
if (result != null) {
throw StateError('Not unique: $name');
}
result = element;
}
}
unit.accept(FunctionAstVisitor(
label: (node) {
updateResult(node.label.staticElement!);
},
));
if (result == null) {
throw StateError('Not found: $name');
}
return result!;
}
FunctionElement localFunction(String name) {
FunctionElement? result;
unit.accept(FunctionAstVisitor(
functionDeclarationStatement: (node) {
var element = node.functionDeclaration.declaredElement;
if (element is FunctionElement && element.name == name) {
if (result != null) {
throw StateError('Not unique: $name');
}
result = element;
}
},
));
if (result == null) {
throw StateError('Not found: $name');
}
return result!;
}
LocalVariableElement localVar(String name) {
LocalVariableElement? result;
void updateResult(Element element) {
if (element is LocalVariableElement && element.name == name) {
if (result != null) {
throw StateError('Not unique: $name');
}
result = element;
}
}
unit.accept(FunctionAstVisitor(
declaredIdentifier: (node) {
updateResult(node.declaredElement!);
},
simpleIdentifier: (node) {
if (node.parent is CatchClause) {
updateResult(node.staticElement!);
}
},
variableDeclaration: (node) {
updateResult(node.declaredElement!);
},
));
if (result == null) {
throw StateError('Not found: $name');
}
return result!;
}
ParameterElement parameter(String name) {
ParameterElement? result;
void findIn(List<ParameterElement> parameters) {
for (var parameter in parameters) {
if (parameter.name == name) {
if (result != null) {
throw StateError('Not unique: $name');
}
result = parameter;
}
}
}
void findInExecutables(List<ExecutableElement> executables) {
for (var executable in executables) {
findIn(executable.parameters);
}
}
findInExecutables(unitElement.accessors);
findInExecutables(unitElement.functions);
for (var alias in unitElement.typeAliases) {
var aliasedElement = alias.aliasedElement;
if (aliasedElement is GenericFunctionTypeElement) {
findIn(aliasedElement.parameters);
}
}
for (var extension_ in unitElement.extensions) {
findInExecutables(extension_.accessors);
findInExecutables(extension_.methods);
}
for (var mixin in unitElement.mixins) {
findInExecutables(mixin.accessors);
findInExecutables(mixin.constructors);
findInExecutables(mixin.methods);
}
for (var class_ in unitElement.types) {
findInExecutables(class_.accessors);
findInExecutables(class_.constructors);
findInExecutables(class_.methods);
}
unit.accept(
FunctionAstVisitor(functionExpression: (node, local) {
if (local) {
var functionElement = node.declaredElement!;
findIn(functionElement.parameters);
}
}),
);
if (result != null) {
return result!;
}
throw StateError('Not found: $name');
}
CompilationUnitElement part(String targetUri) {
CompilationUnitElement? partElement;
for (var part in unitElement.library.parts) {
if (part.uri == targetUri) {
if (partElement != null) {
throw StateError('Not unique: $targetUri');
}
partElement = part;
}
}
if (partElement != null) {
return partElement;
}
throw StateError('Not found: $targetUri');
}
PartFindElement partFind(String targetUri) {
var part = this.part(targetUri);
return PartFindElement(part);
}
PrefixElement prefix(String name) {
for (var import_ in unitElement.library.imports) {
var prefix = import_.prefix;
if (prefix?.name == name) {
return prefix!;
}
}
throw StateError('Not found: $name');
}
TypeParameterElement typeParameter(String name) {
TypeParameterElement? result;
void findIn(List<TypeParameterElement> typeParameters) {
for (var typeParameter in typeParameters) {
if (typeParameter.name == name) {
if (result != null) {
throw StateError('Not unique: $name');
}
result = typeParameter;
}
}
}
void findInClass(ClassElement class_) {
findIn(class_.typeParameters);
for (var method in class_.methods) {
findIn(method.typeParameters);
}
}
for (var type in unitElement.functions) {
findIn(type.typeParameters);
}
for (var alias in unitElement.typeAliases) {
findIn(alias.typeParameters);
var aliasedElement = alias.aliasedElement;
if (aliasedElement is GenericFunctionTypeElement) {
findIn(aliasedElement.typeParameters);
}
}
for (var class_ in unitElement.types) {
findInClass(class_);
}
for (var mixin in unitElement.mixins) {
findInClass(mixin);
}
if (result != null) {
return result!;
}
throw StateError('Not found: $name');
}
}
/// Helper for searching imported elements.
class ImportFindElement extends _FindElementBase {
final ImportElement import;
ImportFindElement(this.import);
LibraryElement get importedLibrary => import.importedLibrary!;
PrefixElement? get prefix => import.prefix;
@override
CompilationUnitElement get unitElement {
return importedLibrary.definingCompilationUnit;
}
}
class PartFindElement extends _FindElementBase {
@override
final CompilationUnitElement unitElement;
PartFindElement(this.unitElement);
}
abstract class _FindElementBase {
CompilationUnitElement get unitElement;
ClassElement class_(String name) {
for (var class_ in unitElement.types) {
if (class_.name == name) {
return class_;
}
}
throw StateError('Not found: $name');
}
ClassElement classOrMixin(String name) {
for (var class_ in unitElement.types) {
if (class_.name == name) {
return class_;
}
}
for (var mixin in unitElement.mixins) {
if (mixin.name == name) {
return mixin;
}
}
throw StateError('Not found: $name');
}
ConstructorElement constructor(String name, {String? of}) {
assert(name != '');
ConstructorElement? result;
for (var class_ in unitElement.types) {
if (of == null || class_.name == of) {
for (var constructor in class_.constructors) {
if (constructor.name == name) {
if (result != null) {
throw StateError('Not unique: $name');
}
result = constructor;
}
}
}
}
if (result != null) {
return result;
}
throw StateError('Not found: $name');
}
ClassElement enum_(String name) {
for (var enum_ in unitElement.enums) {
if (enum_.name == name) {
return enum_;
}
}
throw StateError('Not found: $name');
}
ExtensionElement extension_(String name) {
for (var extension_ in unitElement.extensions) {
if (extension_.name == name) {
return extension_;
}
}
throw StateError('Not found: $name');
}
FieldElement field(String name, {String? of}) {
FieldElement? result;
void findIn(List<FieldElement> fields) {
for (var field in fields) {
if (field.name == name) {
if (result != null) {
throw StateError('Not unique: $name');
}
result = field;
}
}
}
for (var enum_ in unitElement.enums) {
if (of != null && enum_.name != of) {
continue;
}
findIn(enum_.fields);
}
for (var class_ in unitElement.types) {
if (of != null && class_.name != of) {
continue;
}
findIn(class_.fields);
}
for (var mixin in unitElement.mixins) {
if (of != null && mixin.name != of) {
continue;
}
findIn(mixin.fields);
}
for (var extension in unitElement.extensions) {
if (of != null && extension.name != of) {
continue;
}
findIn(extension.fields);
}
if (result != null) {
return result!;
}
throw StateError('Not found: $name');
}
PropertyAccessorElement getter(String name, {String? of}) {
PropertyAccessorElement? result;
void findIn(List<PropertyAccessorElement> accessors) {
for (var accessor in accessors) {
if (accessor.isGetter && accessor.displayName == name) {
if (result != null) {
throw StateError('Not unique: $name');
}
result = accessor;
}
}
}
for (var enum_ in unitElement.enums) {
if (of != null && enum_.name != of) {
continue;
}
findIn(enum_.accessors);
}
for (var extension_ in unitElement.extensions) {
if (of != null && extension_.name != of) {
continue;
}
findIn(extension_.accessors);
}
for (var class_ in unitElement.types) {
if (of != null && class_.name != of) {
continue;
}
findIn(class_.accessors);
}
for (var mixin in unitElement.mixins) {
if (of != null && mixin.name != of) {
continue;
}
findIn(mixin.accessors);
}
if (result != null) {
return result!;
}
throw StateError('Not found: $name');
}
MethodElement method(String name, {String? of}) {
MethodElement? result;
void findIn(List<MethodElement> methods) {
for (var method in methods) {
if (method.name == name) {
if (result != null) {
throw StateError('Not unique: $name');
}
result = method;
}
}
}
for (var extension_ in unitElement.extensions) {
if (of != null && extension_.name != of) {
continue;
}
findIn(extension_.methods);
}
for (var class_ in unitElement.types) {
if (of != null && class_.name != of) {
continue;
}
findIn(class_.methods);
}
for (var mixin in unitElement.mixins) {
if (of != null && mixin.name != of) {
continue;
}
findIn(mixin.methods);
}
if (result != null) {
return result!;
}
throw StateError('Not found: $name');
}
ClassElement mixin(String name) {
for (var mixin in unitElement.mixins) {
if (mixin.name == name) {
return mixin;
}
}
throw StateError('Not found: $name');
}
PropertyAccessorElement setter(String name, {String? of}) {
PropertyAccessorElement? result;
void findIn(List<PropertyAccessorElement> accessors) {
for (var accessor in accessors) {
if (accessor.isSetter && accessor.displayName == name) {
if (result != null) {
throw StateError('Not unique: $name');
}
result = accessor;
}
}
}
for (var extension_ in unitElement.extensions) {
if (of != null && extension_.name != of) {
continue;
}
findIn(extension_.accessors);
}
for (var class_ in unitElement.types) {
if (of != null && class_.name != of) {
continue;
}
findIn(class_.accessors);
}
for (var mixin in unitElement.mixins) {
if (of != null && mixin.name != of) {
continue;
}
findIn(mixin.accessors);
}
if (result != null) {
return result!;
}
throw StateError('Not found: $name');
}
FunctionElement topFunction(String name) {
for (var function in unitElement.functions) {
if (function.name == name) {
return function;
}
}
throw StateError('Not found: $name');
}
PropertyAccessorElement topGet(String name) {
return topVar(name).getter!;
}
PropertyAccessorElement topSet(String name) {
return topVar(name).setter!;
}
TopLevelVariableElement topVar(String name) {
for (var variable in unitElement.topLevelVariables) {
if (variable.name == name) {
return variable;
}
}
throw StateError('Not found: $name');
}
TypeAliasElement typeAlias(String name) {
for (var element in unitElement.typeAliases) {
if (element.name == name) {
return element;
}
}
throw StateError('Not found: $name');
}
ConstructorElement unnamedConstructor(String name) {
return class_(name).unnamedConstructor!;
}
}