// 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. /// Defines element visitors that support useful patterns for visiting the /// elements in an [element model](element.dart). /// /// Dart is an evolving language, and the element model must evolved with it. /// When the element model changes, the visitor interface will sometimes change /// as well. If it is desirable to get a compilation error when the structure of /// the element model has been modified, then you should consider implementing /// the interface [ElementVisitor] directly. Doing so will ensure that changes /// that introduce new classes of elements will be flagged. (Of course, not all /// changes to the element model require the addition of a new class of element, /// and hence cannot be caught this way.) /// /// But if automatic detection of these kinds of changes is not necessary then /// you will probably want to extend one of the classes in this library because /// doing so will simplify the task of writing your visitor and guard against /// future changes to the element model. For example, the /// [RecursiveElementVisitor] automates the process of visiting all of the /// descendants of an element. import 'package:analyzer/dart/element/element.dart'; /// An element visitor that will recursively visit all of the elements in an /// element model (like instances of the class [RecursiveElementVisitor]). In /// addition, when an element of a specific type is visited not only will the /// visit method for that specific type of element be invoked, but additional /// methods for the supertypes of that element will also be invoked. For /// example, using an instance of this class to visit a [MethodElement] will /// cause the method [visitMethodElement] to be invoked but will also cause the /// methods [visitExecutableElement] and [visitElement] to be subsequently /// invoked. This allows visitors to be written that visit all executable /// elements without needing to override the visit method for each of the /// specific subclasses of [ExecutableElement]. /// /// Note, however, that unlike many visitors, element visitors visit objects /// based on the interfaces implemented by those elements. Because interfaces /// form a graph structure rather than a tree structure the way classes do, and /// because it is generally undesirable for an object to be visited more than /// once, this class flattens the interface graph into a pseudo-tree. In /// particular, this class treats elements as if the element types were /// structured in the following way: /// ///
/// Element
///   ClassElement
///   CompilationUnitElement
///   ExecutableElement
///       ConstructorElement
///       LocalElement
///           FunctionElement
///       MethodElement
///       PropertyAccessorElement
///   ExportElement
///   HtmlElement
///   ImportElement
///   LabelElement
///   LibraryElement
///   MultiplyDefinedElement
///   PrefixElement
///   TypeAliasElement
///   TypeParameterElement
///   UndefinedElement
///   VariableElement
///       PropertyInducingElement
///           FieldElement
///           TopLevelVariableElement
///       LocalElement
///           LocalVariableElement
///           ParameterElement
///               FieldFormalParameterElement
/// 
/// /// Subclasses that override a visit method must either invoke the overridden /// visit method or explicitly invoke the more general visit method. Failure to /// do so will cause the visit methods for superclasses of the element to not be /// invoked and will cause the children of the visited node to not be visited. /// /// Clients may extend this class. class GeneralizingElementVisitor implements ElementVisitor { /// Initialize a newly created visitor. const GeneralizingElementVisitor(); @override R? visitClassElement(ClassElement element) => visitElement(element); @override R? visitCompilationUnitElement(CompilationUnitElement element) => visitElement(element); @override R? visitConstructorElement(ConstructorElement element) => visitExecutableElement(element); R? visitElement(Element element) { element.visitChildren(this); return null; } R? visitExecutableElement(ExecutableElement element) => visitElement(element); @override R? visitExportElement(ExportElement element) => visitElement(element); @override R? visitExtensionElement(ExtensionElement element) => visitElement(element); @override R? visitFieldElement(FieldElement element) => visitPropertyInducingElement(element); @override R? visitFieldFormalParameterElement(FieldFormalParameterElement element) => visitParameterElement(element); @override R? visitFunctionElement(FunctionElement element) => visitLocalElement(element); @Deprecated('Override visitTypeAliasElement() instead') @override R? visitFunctionTypeAliasElement(FunctionTypeAliasElement element) => visitElement(element); @override R? visitGenericFunctionTypeElement(GenericFunctionTypeElement element) => visitElement(element); @override R? visitImportElement(ImportElement element) => visitElement(element); @override R? visitLabelElement(LabelElement element) => visitElement(element); @override R? visitLibraryElement(LibraryElement element) => visitElement(element); R? visitLocalElement(LocalElement element) { if (element is LocalVariableElement) { return visitVariableElement(element); } else if (element is ParameterElement) { return visitVariableElement(element); } else if (element is FunctionElement) { return visitExecutableElement(element); } return null; } @override R? visitLocalVariableElement(LocalVariableElement element) => visitLocalElement(element); @override R? visitMethodElement(MethodElement element) => visitExecutableElement(element); @override R? visitMultiplyDefinedElement(MultiplyDefinedElement element) => visitElement(element); @override R? visitParameterElement(ParameterElement element) => visitLocalElement(element); @override R? visitPrefixElement(PrefixElement element) => visitElement(element); @override R? visitPropertyAccessorElement(PropertyAccessorElement element) => visitExecutableElement(element); R? visitPropertyInducingElement(PropertyInducingElement element) => visitVariableElement(element); @override R? visitTopLevelVariableElement(TopLevelVariableElement element) => visitPropertyInducingElement(element); @override R? visitTypeAliasElement(TypeAliasElement element) => visitElement(element); @override R? visitTypeParameterElement(TypeParameterElement element) => visitElement(element); R? visitVariableElement(VariableElement element) => visitElement(element); } /// A visitor that will recursively visit all of the element in an element /// model. For example, using an instance of this class to visit a /// [CompilationUnitElement] will also cause all of the types in the compilation /// unit to be visited. /// /// Subclasses that override a visit method must either invoke the overridden /// visit method or must explicitly ask the visited element to visit its /// children. Failure to do so will cause the children of the visited element to /// not be visited. /// /// Clients may extend this class. class RecursiveElementVisitor implements ElementVisitor { /// Initialize a newly created visitor. const RecursiveElementVisitor(); @override R? visitClassElement(ClassElement element) { element.visitChildren(this); return null; } @override R? visitCompilationUnitElement(CompilationUnitElement element) { element.visitChildren(this); return null; } @override R? visitConstructorElement(ConstructorElement element) { element.visitChildren(this); return null; } @override R? visitExportElement(ExportElement element) { element.visitChildren(this); return null; } @override R? visitExtensionElement(ExtensionElement element) { element.visitChildren(this); return null; } @override R? visitFieldElement(FieldElement element) { element.visitChildren(this); return null; } @override R? visitFieldFormalParameterElement(FieldFormalParameterElement element) { element.visitChildren(this); return null; } @override R? visitFunctionElement(FunctionElement element) { element.visitChildren(this); return null; } @Deprecated('Override visitTypeAliasElement() instead') @override R? visitFunctionTypeAliasElement(FunctionTypeAliasElement element) { element.visitChildren(this); return null; } @override R? visitGenericFunctionTypeElement(GenericFunctionTypeElement element) { element.visitChildren(this); return null; } @override R? visitImportElement(ImportElement element) { element.visitChildren(this); return null; } @override R? visitLabelElement(LabelElement element) { element.visitChildren(this); return null; } @override R? visitLibraryElement(LibraryElement element) { element.visitChildren(this); return null; } @override R? visitLocalVariableElement(LocalVariableElement element) { element.visitChildren(this); return null; } @override R? visitMethodElement(MethodElement element) { element.visitChildren(this); return null; } @override R? visitMultiplyDefinedElement(MultiplyDefinedElement element) { element.visitChildren(this); return null; } @override R? visitParameterElement(ParameterElement element) { element.visitChildren(this); return null; } @override R? visitPrefixElement(PrefixElement element) { element.visitChildren(this); return null; } @override R? visitPropertyAccessorElement(PropertyAccessorElement element) { element.visitChildren(this); return null; } @override R? visitTopLevelVariableElement(TopLevelVariableElement element) { element.visitChildren(this); return null; } @override R? visitTypeAliasElement(TypeAliasElement element) { element.visitChildren(this); return null; } @override R? visitTypeParameterElement(TypeParameterElement element) { element.visitChildren(this); return null; } } /// A visitor that will do nothing when visiting an element. It is intended to /// be a superclass for classes that use the visitor pattern primarily as a /// dispatch mechanism (and hence don't need to recursively visit a whole /// structure) and that only need to visit a small number of element types. /// /// Clients may extend this class. class SimpleElementVisitor implements ElementVisitor { /// Initialize a newly created visitor. const SimpleElementVisitor(); @override R? visitClassElement(ClassElement element) => null; @override R? visitCompilationUnitElement(CompilationUnitElement element) => null; @override R? visitConstructorElement(ConstructorElement element) => null; @override R? visitExportElement(ExportElement element) => null; @override R? visitExtensionElement(ExtensionElement element) => null; @override R? visitFieldElement(FieldElement element) => null; @override R? visitFieldFormalParameterElement(FieldFormalParameterElement element) => null; @override R? visitFunctionElement(FunctionElement element) => null; @Deprecated('Override visitTypeAliasElement() instead') @override R? visitFunctionTypeAliasElement(FunctionTypeAliasElement element) => null; @override R? visitGenericFunctionTypeElement(GenericFunctionTypeElement element) => null; @override R? visitImportElement(ImportElement element) => null; @override R? visitLabelElement(LabelElement element) => null; @override R? visitLibraryElement(LibraryElement element) => null; @override R? visitLocalVariableElement(LocalVariableElement element) => null; @override R? visitMethodElement(MethodElement element) => null; @override R? visitMultiplyDefinedElement(MultiplyDefinedElement element) => null; @override R? visitParameterElement(ParameterElement element) => null; @override R? visitPrefixElement(PrefixElement element) => null; @override R? visitPropertyAccessorElement(PropertyAccessorElement element) => null; @override R? visitTopLevelVariableElement(TopLevelVariableElement element) => null; @override R? visitTypeAliasElement(TypeAliasElement element) => null; @override R? visitTypeParameterElement(TypeParameterElement element) => null; } /// An AST visitor that will throw an exception if any of the visit methods that /// are invoked have not been overridden. It is intended to be a superclass for /// classes that implement the visitor pattern and need to (a) override all of /// the visit methods or (b) need to override a subset of the visit method and /// want to catch when any other visit methods have been invoked. /// /// Clients may extend this class. class ThrowingElementVisitor implements ElementVisitor { /// Initialize a newly created visitor. const ThrowingElementVisitor(); @override R? visitClassElement(ClassElement element) => _throw(element); @override R? visitCompilationUnitElement(CompilationUnitElement element) => _throw(element); @override R? visitConstructorElement(ConstructorElement element) => _throw(element); @override R? visitExportElement(ExportElement element) => _throw(element); @override R? visitExtensionElement(ExtensionElement element) => _throw(element); @override R? visitFieldElement(FieldElement element) => _throw(element); @override R? visitFieldFormalParameterElement(FieldFormalParameterElement element) => _throw(element); @override R? visitFunctionElement(FunctionElement element) => _throw(element); @Deprecated('Override visitTypeAliasElement() instead') @override R? visitFunctionTypeAliasElement(FunctionTypeAliasElement element) => _throw(element); @override R? visitGenericFunctionTypeElement(GenericFunctionTypeElement element) => _throw(element); @override R? visitImportElement(ImportElement element) => _throw(element); @override R? visitLabelElement(LabelElement element) => _throw(element); @override R? visitLibraryElement(LibraryElement element) => _throw(element); @override R? visitLocalVariableElement(LocalVariableElement element) => _throw(element); @override R? visitMethodElement(MethodElement element) => _throw(element); @override R? visitMultiplyDefinedElement(MultiplyDefinedElement element) => _throw(element); @override R? visitParameterElement(ParameterElement element) => _throw(element); @override R? visitPrefixElement(PrefixElement element) => _throw(element); @override R? visitPropertyAccessorElement(PropertyAccessorElement element) => _throw(element); @override R? visitTopLevelVariableElement(TopLevelVariableElement element) => _throw(element); @override R? visitTypeAliasElement(TypeAliasElement element) => _throw(element); @override R? visitTypeParameterElement(TypeParameterElement element) => _throw(element); R _throw(Element element) { throw Exception('Missing implementation of visit${element.runtimeType}'); } }