| // 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); |
| |
| LibraryElement get libraryElement => unitElement.library; |
| |
| @override |
| CompilationUnitElement get unitElement => unit.declaredElement!; |
| |
| ExportElement export(String targetUri) { |
| ExportElement? result; |
| |
| for (var export in libraryElement.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 libraryElement.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!; |
| } |
| |
| @override |
| 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.classes) { |
| 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 libraryElement.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 libraryElement.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.classes) { |
| 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.classes) { |
| if (class_.name == name) { |
| return class_; |
| } |
| } |
| throw StateError('Not found: $name'); |
| } |
| |
| ClassElement classOrMixin(String name) { |
| for (var class_ in unitElement.classes) { |
| 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.classes) { |
| 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.classes) { |
| 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.classes) { |
| 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.classes) { |
| 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'); |
| } |
| |
| ParameterElement parameter(String name) { |
| ParameterElement? result; |
| |
| for (var class_ in unitElement.classes) { |
| for (var constructor in class_.constructors) { |
| for (var parameter in constructor.parameters) { |
| if (parameter.name == name) { |
| if (result != null) { |
| throw StateError('Not unique: $name'); |
| } |
| result = parameter; |
| } |
| } |
| } |
| } |
| |
| if (result != null) { |
| return result; |
| } |
| 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.classes) { |
| 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!; |
| } |
| } |