| // Copyright (c) 2012, 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. |
| |
| library elements; |
| |
| import 'package:front_end/src/fasta/scanner.dart' |
| show Token, isUserDefinableOperator, isMinusOperator; |
| |
| import '../common.dart'; |
| import '../common/resolution.dart' show Resolution; |
| import '../common_elements.dart' show CommonElements; |
| import '../constants/constructors.dart'; |
| import '../constants/expressions.dart'; |
| import '../ordered_typeset.dart' show OrderedTypeSet; |
| import '../resolution/scope.dart' show Scope; |
| import '../resolution/tree_elements.dart' show TreeElements; |
| import '../script.dart'; |
| import '../tree/tree.dart' hide AsyncModifier; |
| import '../universe/call_structure.dart'; |
| import '../util/util.dart'; |
| import '../world.dart' show ClosedWorld; |
| import 'entities.dart'; |
| import 'entity_utils.dart' as utils; |
| import 'jumps.dart'; |
| import 'names.dart'; |
| import 'resolution_types.dart'; |
| import 'types.dart'; |
| import 'visitor.dart' show ElementVisitor; |
| |
| const int STATE_NOT_STARTED = 0; |
| const int STATE_STARTED = 1; |
| const int STATE_DONE = 2; |
| |
| class ElementCategory { |
| /** |
| * Represents things that we don't expect to find when looking in a |
| * scope. |
| */ |
| static const int NONE = 0; |
| |
| /** Field, parameter, or variable. */ |
| static const int VARIABLE = 1; |
| |
| /** Function, method, or foreign function. */ |
| static const int FUNCTION = 2; |
| |
| static const int CLASS = 4; |
| |
| static const int PREFIX = 8; |
| |
| /** Constructor or factory. */ |
| static const int FACTORY = 16; |
| |
| static const int ALIAS = 32; |
| |
| static const int SUPER = 64; |
| |
| /** Type variable */ |
| static const int TYPE_VARIABLE = 128; |
| |
| static const int IMPLIES_TYPE = CLASS | ALIAS | TYPE_VARIABLE; |
| } |
| |
| class ElementKind { |
| final String id; |
| final int category; |
| |
| const ElementKind(String this.id, this.category); |
| |
| static const ElementKind VARIABLE = |
| const ElementKind('variable', ElementCategory.VARIABLE); |
| static const ElementKind PARAMETER = |
| const ElementKind('parameter', ElementCategory.VARIABLE); |
| // Parameters in constructors that directly initialize fields. For example: |
| // [:A(this.field):]. |
| static const ElementKind INITIALIZING_FORMAL = |
| const ElementKind('initializing_formal', ElementCategory.VARIABLE); |
| static const ElementKind FUNCTION = |
| const ElementKind('function', ElementCategory.FUNCTION); |
| static const ElementKind CLASS = |
| const ElementKind('class', ElementCategory.CLASS); |
| static const ElementKind GENERATIVE_CONSTRUCTOR = |
| const ElementKind('generative_constructor', ElementCategory.FACTORY); |
| static const ElementKind FACTORY_CONSTRUCTOR = |
| const ElementKind('factory_constructor', ElementCategory.FACTORY); |
| static const ElementKind FIELD = |
| const ElementKind('field', ElementCategory.VARIABLE); |
| static const ElementKind GENERATIVE_CONSTRUCTOR_BODY = |
| const ElementKind('generative_constructor_body', ElementCategory.NONE); |
| static const ElementKind COMPILATION_UNIT = |
| const ElementKind('compilation_unit', ElementCategory.NONE); |
| static const ElementKind GETTER = |
| const ElementKind('getter', ElementCategory.NONE); |
| static const ElementKind SETTER = |
| const ElementKind('setter', ElementCategory.NONE); |
| static const ElementKind TYPE_VARIABLE = |
| const ElementKind('type_variable', ElementCategory.TYPE_VARIABLE); |
| static const ElementKind ABSTRACT_FIELD = |
| const ElementKind('abstract_field', ElementCategory.VARIABLE); |
| static const ElementKind LIBRARY = |
| const ElementKind('library', ElementCategory.NONE); |
| static const ElementKind IMPORT = |
| const ElementKind('import', ElementCategory.NONE); |
| static const ElementKind EXPORT = |
| const ElementKind('export', ElementCategory.NONE); |
| static const ElementKind PREFIX = |
| const ElementKind('prefix', ElementCategory.PREFIX); |
| static const ElementKind TYPEDEF = |
| const ElementKind('typedef', ElementCategory.ALIAS); |
| |
| static const ElementKind AMBIGUOUS = |
| const ElementKind('ambiguous', ElementCategory.NONE); |
| static const ElementKind WARN_ON_USE = |
| const ElementKind('warn_on_use', ElementCategory.NONE); |
| static const ElementKind ERROR = |
| const ElementKind('error', ElementCategory.NONE); |
| |
| toString() => id; |
| } |
| |
| /** |
| * A declared element of a program. |
| * |
| * The declared elements of a program include classes, methods, |
| * fields, variables, parameters, etc. |
| * |
| * Sometimes it makes sense to construct "synthetic" elements that |
| * have not been declared anywhere in a program, for example, there |
| * are elements corresponding to "dynamic", "null", and unresolved |
| * references. |
| * |
| * Elements are distinct from types ([ResolutionDartType]). For example, there |
| * is one declaration of the class List, but several related types, |
| * for example, List, List<int>, List<String>, etc. |
| * |
| * Elements are distinct from AST nodes ([Node]), and there normally is a |
| * one-to-one correspondence between an AST node and an element |
| * (except that not all kinds of AST nodes have an associated |
| * element). |
| * |
| * AST nodes represent precisely what is written in source code, for |
| * example, when a user writes "class MyClass {}", the corresponding |
| * AST node does not have a superclass. On the other hand, the |
| * corresponding element (once fully resolved) will record the |
| * information about the implicit superclass as defined by the |
| * language semantics. |
| * |
| * Generally, the contents of a method are represented as AST nodes |
| * without additional elements, but things like local functions, local |
| * variables, and labels have a corresponding element. |
| * |
| * We generally say that scanning, parsing, resolution, and type |
| * checking comprise the "front-end" of the compiler. The "back-end" |
| * includes things like SSA graph construction, optimizations, and |
| * code generation. |
| * |
| * The front-end data structures are designed to be reusable by |
| * several back-ends. For example, we may want to support emitting |
| * minified Dart and JavaScript code in one go. Also, we're planning |
| * on adding an incremental compilation server that should be able to |
| * reuse elements between compilations. So to keep things simple, it |
| * is best if the backends avoid setting state directly in elements. |
| * It is better to keep such state in a table on the side. |
| */ |
| abstract class Element implements Entity { |
| String get name; |
| ElementKind get kind; |
| Element get enclosingElement; |
| Iterable<MetadataAnnotation> get metadata; |
| |
| /// `true` if this element is a library. |
| bool get isLibrary; |
| |
| /// `true` if this element is an import declaration. |
| bool get isImport => kind == ElementKind.IMPORT; |
| |
| /// `true` if this element is an export declaration. |
| bool get isExport => kind == ElementKind.EXPORT; |
| |
| /// `true` if this element is a compilation unit. |
| bool get isCompilationUnit; |
| |
| /// `true` if this element is defines the scope of prefix used by one or |
| /// more import declarations. |
| bool get isPrefix; |
| |
| /// `true` if this element is a class declaration or a mixin application. |
| bool get isClass; |
| |
| /// `true` if this element is a type variable declaration. |
| bool get isTypeVariable; |
| |
| /// `true` if this element is a typedef declaration. |
| bool get isTypedef; |
| |
| /// `true` if this element is a top level function, static or instance |
| /// method, local function or closure defined by a function expression. |
| /// |
| /// This property is `true` for operator methods but `false` for getter and |
| /// setter methods, and generative and factory constructors. |
| /// |
| /// See also [isConstructor], [isGenerativeConstructor], and |
| /// [isFactoryConstructor] for constructor properties, and [isAccessor], |
| /// [isGetter] and [isSetter] for getter/setter properties. |
| bool get isFunction; |
| |
| /// `true` if this element is an operator method. |
| bool get isOperator; |
| |
| /// `true` if this element is an accessor, that is either an explicit |
| /// getter or an explicit setter. |
| bool get isAccessor; |
| |
| /// `true` if this element is an explicit getter method. |
| bool get isGetter; |
| |
| /// `true` if this element is an explicit setter method. |
| bool get isSetter; |
| |
| /// `true` if this element is a generative or factory constructor. |
| bool get isConstructor; |
| |
| /// `true` if this element is a generative constructor, potentially |
| /// redirecting. |
| bool get isGenerativeConstructor; |
| |
| /// `true` if this element is the body of a generative constructor. |
| /// |
| /// This is a synthetic element kind used only by the JavaScript backend. |
| bool get isGenerativeConstructorBody; |
| |
| /// `true` if this element is a factory constructor, |
| /// potentially redirecting. |
| bool get isFactoryConstructor; |
| |
| /// `true` if this element is a local variable. |
| bool get isVariable; |
| |
| /// `true` if this element is a top level variable, static or instance field. |
| bool get isField; |
| |
| /// `true` if this element is the abstract field implicitly defined by an |
| /// explicit getter and/or setter. |
| bool get isAbstractField; |
| |
| /// `true` if this element is a formal parameter from a constructor, |
| /// a method, a typedef declaration, or from an inlined function typed |
| /// parameter. |
| /// |
| /// This property is `false` if this element is an initializing formal. |
| /// See [isInitializingFormal]. |
| bool get isRegularParameter; |
| |
| /// `true` if this element is an initializing formal of constructor, that |
| /// is a formal of the form `this.foo`. |
| bool get isInitializingFormal; |
| |
| /// `true` if this element is a formal parameter, either regular or |
| /// initializing. |
| bool get isParameter => isRegularParameter || isInitializingFormal; |
| |
| /// `true` if this element represents a resolution error. |
| bool get isError; |
| |
| /// `true` if this element represents an ambiguous name. |
| /// |
| /// Ambiguous names occur when two imports/exports contain different entities |
| /// by the same name. If an ambiguous name is resolved an warning or error |
| /// is produced. |
| bool get isAmbiguous; |
| |
| /// True if there has been errors during resolution or parsing of this |
| /// element. |
| bool get isMalformed; |
| |
| /// `true` if this element represents an entity whose access causes one or |
| /// more warnings. |
| bool get isWarnOnUse; |
| |
| bool get isClosure; |
| |
| /// `true` if the element is a (static or instance) member of a class. |
| /// |
| /// Members are constructors, methods and fields. |
| bool get isClassMember; |
| |
| /// `true` if the element is a nonstatic member of a class. |
| /// |
| /// Instance members are methods and fields but not constructors. |
| bool get isInstanceMember; |
| |
| /// Returns true if this [Element] is a top level element. |
| /// That is, if it is not defined within the scope of a class. |
| /// |
| /// This means whether the enclosing element is a compilation unit. |
| /// With the exception of [ClosureClassElement] that is considered top level |
| /// as all other classes. |
| bool get isTopLevel; |
| bool get isAssignable; |
| |
| bool get isDeferredLoaderGetter; |
| |
| /// True if the element is declared in a patch library but has no |
| /// corresponding declaration in the origin library. |
| bool get isInjected; |
| |
| /// `true` if this element is a constructor, top level or local variable, |
| /// or static field that is declared `const`. |
| bool get isConst; |
| |
| /// `true` if this element is a top level or local variable, static or |
| /// instance field, or parameter that is declared `final`. |
| bool get isFinal; |
| |
| /// `true` if this element is a method, getter, setter or field that |
| /// is declared `static`. |
| bool get isStatic; |
| |
| /// `true` if this element is local element, that is, a local variable, |
| /// local function or parameter. |
| bool get isLocal; |
| |
| bool get impliesType; |
| |
| /// The character offset of the declaration of this element within its |
| /// compilation unit, if available. |
| /// |
| /// This is used to sort the elements. |
| int get sourceOffset; |
| |
| // TODO(johnniwinther): Remove this. |
| Token get position; |
| |
| /// The position of the declaration of this element, if available. |
| SourceSpan get sourcePosition; |
| |
| CompilationUnitElement get compilationUnit; |
| LibraryElement get library; |
| LibraryElement get implementationLibrary; |
| ClassElement get enclosingClass; |
| Element get enclosingClassOrCompilationUnit; |
| Element get outermostEnclosingMemberOrTopLevel; |
| |
| // TODO(johnniwinther): Replace uses of this with [enclosingClass] when |
| // [ClosureClassElement] has been removed. |
| /// The enclosing class that defines the type environment for this element. |
| ClassElement get contextClass; |
| |
| FunctionElement asFunctionElement(); |
| |
| /// Is [:true:] if this element has a corresponding patch. |
| /// |
| /// If [:true:] this element has a non-null [patch] field. |
| /// |
| /// See [:patch_parser.dart:] for a description of the terminology. |
| bool get isPatched; |
| |
| /// Is [:true:] if this element is a patch. |
| /// |
| /// If [:true:] this element has a non-null [origin] field. |
| /// |
| /// See [:patch_parser.dart:] for a description of the terminology. |
| bool get isPatch; |
| |
| /// Is [:true:] if this element defines the implementation for the entity of |
| /// this element. |
| /// |
| /// See [:patch_parser.dart:] for a description of the terminology. |
| bool get isImplementation; |
| |
| /// Is [:true:] if this element introduces the entity of this element. |
| /// |
| /// See [:patch_parser.dart:] for a description of the terminology. |
| bool get isDeclaration; |
| |
| /// Returns the element which defines the implementation for the entity of |
| /// this element. |
| /// |
| /// See [:patch_parser.dart:] for a description of the terminology. |
| Element get implementation; |
| |
| /// Returns the element which introduces the entity of this element. |
| /// |
| /// See [:patch_parser.dart:] for a description of the terminology. |
| Element get declaration; |
| |
| /// Returns the patch for this element if this element is patched. |
| /// |
| /// See [:patch_parser.dart:] for a description of the terminology. |
| Element get patch; |
| |
| /// Returns the origin for this element if this element is a patch. |
| /// |
| /// See [:patch_parser.dart:] for a description of the terminology. |
| Element get origin; |
| |
| bool get isSynthesized; |
| bool get isMixinApplication; |
| |
| bool get isAbstract; |
| |
| Scope buildScope(); |
| |
| // TODO(johnniwinther): Move this to [AstElement]. |
| /// Returns the [Element] that holds the [TreeElements] for this element. |
| AnalyzableElement get analyzableElement; |
| |
| accept(ElementVisitor visitor, arg); |
| } |
| |
| class Elements { |
| static bool isUnresolved(Element e) { |
| return e == null || e.isMalformed; |
| } |
| |
| static bool isError(Element e) { |
| return e != null && e.isError; |
| } |
| |
| static bool isMalformed(Element e) { |
| return e != null && e.isMalformed; |
| } |
| |
| /// Unwraps [element] reporting any warnings attached to it, if any. |
| static Element unwrap( |
| Element element, DiagnosticReporter listener, Spannable spannable) { |
| if (element != null && element.isWarnOnUse) { |
| WarnOnUseElement wrappedElement = element; |
| element = wrappedElement.unwrap(listener, spannable); |
| } |
| return element; |
| } |
| |
| static bool isClass(Element e) => e != null && e.kind == ElementKind.CLASS; |
| static bool isTypedef(Element e) { |
| return e != null && e.kind == ElementKind.TYPEDEF; |
| } |
| |
| static bool isLocal(Element element) { |
| return !Elements.isUnresolved(element) && element.isLocal; |
| } |
| |
| static bool isInstanceField(Element element) { |
| return !Elements.isUnresolved(element) && |
| element.isInstanceMember && |
| (identical(element.kind, ElementKind.FIELD) || |
| identical(element.kind, ElementKind.GETTER) || |
| identical(element.kind, ElementKind.SETTER)); |
| } |
| |
| static bool isStaticOrTopLevel(Element element) { |
| // TODO(johnniwinther): Clean this up. This currently returns true for a |
| // PartialConstructorElement, SynthesizedConstructorElementX, and |
| // TypeVariableElementX though neither `element.isStatic` nor |
| // `element.isTopLevel` is true. |
| if (Elements.isUnresolved(element)) return false; |
| if (element.isStatic || element.isTopLevel) return true; |
| return !element.isAmbiguous && |
| !element.isInstanceMember && |
| !element.isPrefix && |
| element.enclosingElement != null && |
| (element.enclosingElement.kind == ElementKind.CLASS || |
| element.enclosingElement.kind == ElementKind.COMPILATION_UNIT || |
| element.enclosingElement.kind == ElementKind.LIBRARY || |
| element.enclosingElement.kind == ElementKind.PREFIX); |
| } |
| |
| static bool isInStaticContext(Element element) { |
| if (isUnresolved(element)) return true; |
| if (element.enclosingElement.isClosure) { |
| dynamic closureClass = element.enclosingElement; |
| // ignore: UNDEFINED_GETTER |
| element = closureClass.methodElement; |
| } |
| Element outer = element.outermostEnclosingMemberOrTopLevel; |
| if (isUnresolved(outer)) return true; |
| if (outer.isTopLevel) return true; |
| if (outer.isGenerativeConstructor) return false; |
| if (outer.isInstanceMember) return false; |
| return true; |
| } |
| |
| static bool hasAccessToTypeVariable( |
| Element element, TypeVariableElement typeVariable) { |
| GenericElement declaration = typeVariable.typeDeclaration; |
| if (declaration is FunctionElement || declaration is ParameterElement) { |
| return true; |
| } |
| Element outer = element.outermostEnclosingMemberOrTopLevel; |
| return (outer != null && outer.isFactoryConstructor) || |
| !isInStaticContext(element); |
| } |
| |
| static bool isStaticOrTopLevelField(Element element) { |
| return isStaticOrTopLevel(element) && |
| (identical(element.kind, ElementKind.FIELD) || |
| identical(element.kind, ElementKind.GETTER) || |
| identical(element.kind, ElementKind.SETTER)); |
| } |
| |
| static bool isStaticOrTopLevelFunction(Element element) { |
| return isStaticOrTopLevel(element) && element.isFunction; |
| } |
| |
| static bool isInstanceMethod(Element element) { |
| return !Elements.isUnresolved(element) && |
| element.isInstanceMember && |
| (identical(element.kind, ElementKind.FUNCTION)); |
| } |
| |
| static bool isInstanceSend(Send send, TreeElements elements) { |
| Element element = elements[send]; |
| if (element == null) return !isClosureSend(send, element); |
| return isInstanceMethod(element) || |
| isInstanceField(element) || |
| (send.isConditional && !element.isStatic); |
| } |
| |
| static bool isClosureSend(Send send, Element element) { |
| if (send.isPropertyAccess) return false; |
| if (send.receiver != null) return false; |
| Node selector = send.selector; |
| // this(). |
| if (selector.isThis()) return true; |
| // (o)() or foo()(). |
| if (element == null && selector.asIdentifier() == null) return true; |
| if (element == null) return false; |
| // foo() with foo a local or a parameter. |
| return isLocal(element); |
| } |
| |
| static String reconstructConstructorNameSourceString(FunctionEntity element) { |
| if (element.name == '') { |
| return element.enclosingClass.name; |
| } else { |
| return utils.reconstructConstructorName(element); |
| } |
| } |
| |
| static String constructorNameForDiagnostics( |
| String className, String constructorName) { |
| String classNameString = className; |
| String constructorNameString = constructorName; |
| return (constructorName == '') |
| ? classNameString |
| : "$classNameString.$constructorNameString"; |
| } |
| |
| /// Returns `true` if [name] is the name of an operator method. |
| static bool isOperatorName(String name) { |
| return name == 'unary-' || isUserDefinableOperator(name); |
| } |
| |
| /** |
| * Map an operator-name to a valid JavaScript identifier. |
| * |
| * For non-operator names, this method just returns its input. |
| * |
| * The results returned from this method are guaranteed to be valid |
| * JavaScript identifiers, except it may include reserved words for |
| * non-operator names. |
| */ |
| static String operatorNameToIdentifier(String name) { |
| if (name == null) { |
| return name; |
| } else if (name == '==') { |
| return r'operator$eq'; |
| } else if (name == '~') { |
| return r'operator$not'; |
| } else if (name == '[]') { |
| return r'operator$index'; |
| } else if (name == '[]=') { |
| return r'operator$indexSet'; |
| } else if (name == '*') { |
| return r'operator$mul'; |
| } else if (name == '/') { |
| return r'operator$div'; |
| } else if (name == '%') { |
| return r'operator$mod'; |
| } else if (name == '~/') { |
| return r'operator$tdiv'; |
| } else if (name == '+') { |
| return r'operator$add'; |
| } else if (name == '<<') { |
| return r'operator$shl'; |
| } else if (name == '>>') { |
| return r'operator$shr'; |
| } else if (name == '>=') { |
| return r'operator$ge'; |
| } else if (name == '>') { |
| return r'operator$gt'; |
| } else if (name == '<=') { |
| return r'operator$le'; |
| } else if (name == '<') { |
| return r'operator$lt'; |
| } else if (name == '&') { |
| return r'operator$and'; |
| } else if (name == '^') { |
| return r'operator$xor'; |
| } else if (name == '|') { |
| return r'operator$or'; |
| } else if (name == '-') { |
| return r'operator$sub'; |
| } else if (name == 'unary-') { |
| return r'operator$negate'; |
| } else { |
| return name; |
| } |
| } |
| |
| static String constructOperatorNameOrNull(String op, bool isUnary) { |
| if (isMinusOperator(op)) { |
| return isUnary ? 'unary-' : op; |
| } else if (isUserDefinableOperator(op) || op == '??') { |
| return op; |
| } else { |
| return null; |
| } |
| } |
| |
| static String constructOperatorName(String op, bool isUnary) { |
| String operatorName = constructOperatorNameOrNull(op, isUnary); |
| if (operatorName == null) |
| throw 'Unhandled operator: $op'; |
| else |
| return operatorName; |
| } |
| |
| static String mapToUserOperatorOrNull(String op) { |
| if (identical(op, '!=')) return '=='; |
| if (identical(op, '*=')) return '*'; |
| if (identical(op, '/=')) return '/'; |
| if (identical(op, '%=')) return '%'; |
| if (identical(op, '~/=')) return '~/'; |
| if (identical(op, '+=')) return '+'; |
| if (identical(op, '-=')) return '-'; |
| if (identical(op, '<<=')) return '<<'; |
| if (identical(op, '>>=')) return '>>'; |
| if (identical(op, '&=')) return '&'; |
| if (identical(op, '^=')) return '^'; |
| if (identical(op, '|=')) return '|'; |
| if (identical(op, '??=')) return '??'; |
| |
| return null; |
| } |
| |
| /// If `true`, members are sorted using their implementation fileUri. |
| /// |
| /// This is used for ensuring equivalent output order when testing against |
| /// .dill. |
| // TODO(johnniwinther): Remove this when patching correctly stores origin and |
| // patch file uris (issue 31579) |
| static bool useCFEOrder = false; |
| |
| /// A `compareTo` function that places [Element]s in a consistent order based |
| /// on the source code order. |
| static int compareByPosition(Element a, Element b) { |
| if (identical(a, b)) return 0; |
| if (useCFEOrder) { |
| if (a is MethodElement) { |
| a = a.implementation; |
| } |
| if (b is MethodElement) { |
| b = b.implementation; |
| } |
| } |
| int r = utils.compareLibrariesUris( |
| a.library.canonicalUri, b.library.canonicalUri); |
| if (r != 0) return r; |
| Uri aUri = a.compilationUnit.script.readableUri; |
| Uri bUri = b.compilationUnit.script.readableUri; |
| r = utils.compareSourceUris(aUri, bUri); |
| if (r != 0) return r; |
| return utils.compareEntities(a, a.sourceOffset, -1, b, b.sourceOffset, -1); |
| } |
| |
| static List<E> sortedByPosition<E extends Element>(Iterable<E> elements) { |
| return elements.toList()..sort(compareByPosition); |
| } |
| |
| static bool isFixedListConstructorCall( |
| ConstructorEntity element, Send node, CommonElements commonElements) { |
| return commonElements.isUnnamedListConstructor(element) && |
| node.isCall && |
| !node.arguments.isEmpty && |
| node.arguments.tail.isEmpty; |
| } |
| |
| static bool isGrowableListConstructorCall( |
| ConstructorEntity element, Send node, CommonElements commonElements) { |
| return commonElements.isUnnamedListConstructor(element) && |
| node.isCall && |
| node.arguments.isEmpty; |
| } |
| |
| static bool isFilledListConstructorCall( |
| ConstructorEntity element, Send node, CommonElements commonElements) { |
| return commonElements.isFilledListConstructor(element) && |
| node.isCall && |
| !node.arguments.isEmpty && |
| !node.arguments.tail.isEmpty && |
| node.arguments.tail.tail.isEmpty; |
| } |
| |
| static bool isConstructorOfTypedArraySubclass( |
| Element element, ClosedWorld closedWorld) { |
| if (closedWorld.commonElements.typedDataLibrary == null) return false; |
| if (!element.isConstructor) return false; |
| ConstructorElement constructor = element.implementation; |
| constructor = constructor.effectiveTarget; |
| ClassElement cls = constructor.enclosingClass; |
| return cls.library == closedWorld.commonElements.typedDataLibrary && |
| closedWorld.nativeData.isNativeClass(cls) && |
| closedWorld.isSubtypeOf( |
| cls, closedWorld.commonElements.typedDataClass) && |
| closedWorld.isSubtypeOf(cls, closedWorld.commonElements.listClass) && |
| constructor.name == ''; |
| } |
| |
| static bool switchStatementHasContinue( |
| SwitchStatement node, TreeElements elements) { |
| for (SwitchCase switchCase in node.cases) { |
| for (Node labelOrCase in switchCase.labelsAndCases) { |
| Node label = labelOrCase.asLabel(); |
| if (label != null) { |
| LabelDefinition labelElement = elements.getLabelDefinition(label); |
| if (labelElement != null && labelElement.isContinueTarget) { |
| return true; |
| } |
| } |
| } |
| } |
| return false; |
| } |
| |
| static bool isUnusedLabel(LabeledStatement node, TreeElements elements) { |
| Node body = node.statement; |
| JumpTarget element = elements.getTargetDefinition(body); |
| // Labeled statements with no element on the body have no breaks. |
| // A different target statement only happens if the body is itself |
| // a break or continue for a different target. In that case, this |
| // label is also always unused. |
| return element == null || element.statement != body; |
| } |
| |
| /** |
| * Returns a `List` with the evaluated arguments in the normalized order. |
| * |
| * [compileDefaultValue] is a function that returns a compiled constant |
| * of an optional argument that is not in [compiledArguments]. |
| * |
| * Precondition: `callStructure.signatureApplies(element.type)`. |
| * |
| * Invariant: [element] must be the implementation element. |
| */ |
| static List<T> makeArgumentsList<T>( |
| CallStructure callStructure, |
| Link<Node> arguments, |
| FunctionElement element, |
| T compileArgument(Node argument), |
| T compileDefaultValue(ParameterElement element)) { |
| assert(element.isImplementation, failedAt(element)); |
| List<T> result = <T>[]; |
| |
| FunctionSignature parameters = element.functionSignature; |
| parameters.forEachRequiredParameter((_) { |
| result.add(compileArgument(arguments.head)); |
| arguments = arguments.tail; |
| }); |
| |
| if (!parameters.optionalParametersAreNamed) { |
| parameters.forEachOptionalParameter((_element) { |
| ParameterElement element = _element; |
| if (!arguments.isEmpty) { |
| result.add(compileArgument(arguments.head)); |
| arguments = arguments.tail; |
| } else { |
| result.add(compileDefaultValue(element)); |
| } |
| }); |
| } else { |
| // Visit named arguments and add them into a temporary list. |
| List compiledNamedArguments = []; |
| for (; !arguments.isEmpty; arguments = arguments.tail) { |
| NamedArgument namedArgument = arguments.head; |
| compiledNamedArguments.add(compileArgument(namedArgument.expression)); |
| } |
| // Iterate over the optional parameters of the signature, and try to |
| // find them in [compiledNamedArguments]. If found, we use the |
| // value in the temporary list, otherwise the default value. |
| parameters.orderedOptionalParameters.forEach((_element) { |
| ParameterElement element = _element; |
| int foundIndex = callStructure.namedArguments.indexOf(element.name); |
| if (foundIndex != -1) { |
| result.add(compiledNamedArguments[foundIndex]); |
| } else { |
| result.add(compileDefaultValue(element)); |
| } |
| }); |
| } |
| return result; |
| } |
| |
| /** |
| * Fills [list] with the arguments in the order expected by |
| * [callee], and where [caller] is a synthesized element |
| * |
| * [compileArgument] is a function that returns a compiled version |
| * of a parameter of [callee]. |
| * |
| * [compileConstant] is a function that returns a compiled constant |
| * of an optional argument that is not in the parameters of [callee]. |
| * |
| * Returns [:true:] if the signature of the [caller] matches the |
| * signature of the [callee], [:false:] otherwise. |
| */ |
| static bool addForwardingElementArgumentsToList<T>( |
| ConstructorElement caller, |
| List<T> list, |
| ConstructorElement callee, |
| T compileArgument(ParameterElement element), |
| T compileConstant(ParameterElement element)) { |
| assert( |
| !callee.isMalformed, |
| failedAt( |
| caller, |
| "Cannot compute arguments to malformed constructor: " |
| "$caller calling $callee.")); |
| |
| FunctionSignature signature = caller.functionSignature; |
| Map<Node, ParameterElement> mapping = <Node, ParameterElement>{}; |
| |
| // TODO(ngeoffray): This is a hack that fakes up AST nodes, so |
| // that we can call [addArgumentsToList]. |
| Link<Node> computeCallNodesFromParameters() { |
| LinkBuilder<Node> builder = new LinkBuilder<Node>(); |
| signature.forEachRequiredParameter((_element) { |
| ParameterElement element = _element; |
| Node node = element.node; |
| mapping[node] = element; |
| builder.addLast(node); |
| }); |
| if (signature.optionalParametersAreNamed) { |
| signature.forEachOptionalParameter((_element) { |
| ParameterElement element = _element; |
| mapping[element.initializer] = element; |
| builder.addLast(new NamedArgument(null, null, element.initializer)); |
| }); |
| } else { |
| signature.forEachOptionalParameter((_element) { |
| ParameterElement element = _element; |
| Node node = element.node; |
| mapping[node] = element; |
| builder.addLast(node); |
| }); |
| } |
| return builder.toLink(); |
| } |
| |
| T internalCompileArgument(Node node) { |
| return compileArgument(mapping[node]); |
| } |
| |
| Link<Node> nodes = computeCallNodesFromParameters(); |
| |
| // Synthesize a structure for the call. |
| // TODO(ngeoffray): Should the resolver do it instead? |
| CallStructure callStructure = new CallStructure( |
| signature.parameterCount, signature.type.namedParameters); |
| if (!callStructure.signatureApplies(signature.parameterStructure)) { |
| return false; |
| } |
| list.addAll(makeArgumentsList<T>(callStructure, nodes, callee, |
| internalCompileArgument, compileConstant)); |
| |
| return true; |
| } |
| } |
| |
| /// An element representing an erroneous resolution. |
| /// |
| /// An [ErroneousElement] is used instead of `null` to provide additional |
| /// information about the error that caused the element to be unresolvable |
| /// or otherwise invalid. |
| /// |
| /// Accessing any field or calling any method defined on [ErroneousElement] |
| /// except [isError] will currently throw an exception. (This might |
| /// change when we actually want more information on the erroneous element, |
| /// e.g., the name of the element we were trying to resolve.) |
| /// |
| /// Code that cannot not handle an [ErroneousElement] should use |
| /// `Element.isUnresolved(element)` to check for unresolvable elements instead |
| /// of `element == null`. |
| // ignore: STRONG_MODE_INVALID_METHOD_OVERRIDE_FROM_BASE |
| abstract class ErroneousElement extends Element implements ConstructorElement { |
| MessageKind get messageKind; |
| Map get messageArguments; |
| String get message; |
| } |
| |
| /// An [Element] whose usage should cause one or more warnings. |
| abstract class WarnOnUseElement extends Element { |
| /// The element whose usage cause a warning. |
| Element get wrappedElement; |
| |
| /// Reports the attached warning and returns the wrapped element. |
| /// [usageSpannable] is used to report messages on the reference of |
| /// [wrappedElement]. |
| Element unwrap(DiagnosticReporter listener, Spannable usageSpannable); |
| } |
| |
| /// An ambiguous element represents multiple elements accessible by the same |
| /// name. |
| /// |
| /// Ambiguous elements are created during handling of import/export scopes. If |
| /// an ambiguous element is encountered during resolution a warning/error is |
| /// reported. |
| abstract class AmbiguousElement extends Element { |
| MessageKind get messageKind; |
| Map get messageArguments; |
| Element get existingElement; |
| Element get newElement; |
| |
| /// Compute the info messages associated with an error/warning on [context]. |
| List<DiagnosticMessage> computeInfos( |
| Element context, DiagnosticReporter listener); |
| } |
| |
| // TODO(kasperl): This probably shouldn't be called an element. It's |
| // just an interface shared by classes and libraries. |
| abstract class ScopeContainerElement implements Element { |
| Element localLookup(String elementName); |
| |
| void forEachLocalMember(f(Element element)); |
| } |
| |
| abstract class CompilationUnitElement extends Element { |
| /// Use [library] instead. |
| @deprecated |
| get enclosingElement; |
| |
| Script get script; |
| |
| void forEachLocalMember(f(Element element)); |
| } |
| |
| abstract class ImportElement extends Element implements ImportEntity { |
| Uri get uri; |
| LibraryElement get importedLibrary; |
| LibraryElement get enclosingLibrary => library; |
| bool get isDeferred; |
| PrefixElement get prefix; |
| String get name; |
| // TODO(johnniwinther): Remove this when no longer needed in source mirrors. |
| Import get node; |
| } |
| |
| abstract class ExportElement extends Element { |
| Uri get uri; |
| LibraryElement get exportedLibrary; |
| // TODO(johnniwinther): Remove this when no longer needed in source mirrors. |
| Export get node; |
| } |
| |
| abstract class LibraryElement extends Element |
| implements ScopeContainerElement, AnalyzableElement, LibraryEntity { |
| /** |
| * The canonical uri for this library. |
| * |
| * For user libraries the canonical uri is the script uri. For platform |
| * libraries the canonical uri is of the form [:dart:x:]. |
| */ |
| Uri get canonicalUri; |
| |
| /// Returns `true` if this library is 'dart:core'. |
| bool get isDartCore; |
| |
| CompilationUnitElement get entryCompilationUnit; |
| Link<CompilationUnitElement> get compilationUnits; |
| |
| /// The import declarations in this library, including the implicit import of |
| /// 'dart:core', if present. |
| Iterable<ImportElement> get imports; |
| |
| /// The export declarations in this library. |
| Iterable<ExportElement> get exports; |
| |
| /** |
| * [:true:] if this library is part of the platform, that is, its canonical |
| * uri has the scheme 'dart'. |
| */ |
| bool get isPlatformLibrary; |
| |
| /** |
| * [:true:] if this library is from a package, that is, its canonical uri has |
| * the scheme 'package'. |
| */ |
| bool get isPackageLibrary; |
| |
| /** |
| * [:true:] if this library is a platform library whose path starts with |
| * an underscore. |
| */ |
| bool get isInternalLibrary; |
| |
| bool get exportsHandled; |
| |
| LibraryElement get implementation; |
| |
| Element find(String elementName); |
| Element findLocal(String elementName); |
| Element findExported(String elementName); |
| void forEachExport(f(Element element)); |
| |
| /// Calls [f] for each [Element] imported into this library. |
| void forEachImport(f(Element element)); |
| |
| /// Returns the imports that import element into this library. |
| Iterable<ImportElement> getImportsFor(Element element); |
| |
| /// `true` if this library has name as given through a library tag. |
| bool get hasLibraryName; |
| |
| /// The library name, which is either the name given in the library tag |
| /// or the empty string if there is no library tag. |
| String get libraryName; |
| |
| /// Returns the library name (as defined by the library tag) or for scripts |
| /// (which have no library tag) the script file name. |
| /// |
| /// Note: the returned filename is still escaped ("a%20b.dart" instead of |
| /// "a b.dart"). |
| String get name; |
| } |
| |
| /// The implicit scope defined by a import declaration with a prefix clause. |
| abstract class PrefixElement extends Element { |
| Element lookupLocalMember(String memberName); |
| |
| void forEachLocalMember(void f(Element member)); |
| |
| /// Is true if this prefix belongs to a deferred import. |
| bool get isDeferred; |
| |
| /// Import that declared this deferred prefix. |
| ImportElement get deferredImport; |
| |
| /// The `loadLibrary` getter implicitly defined on deferred prefixes. |
| GetterElement get loadLibrary; |
| } |
| |
| /// A type alias definition. |
| abstract class TypedefElement extends Element |
| implements |
| AstElement, |
| TypeDeclarationElement, |
| FunctionTypedElement, |
| TypedefEntity { |
| /// The type defined by this typedef with the type variables as its type |
| /// arguments. |
| /// |
| /// For instance `F<T>` for `typedef void F<T>(T t)`. |
| ResolutionTypedefType get thisType; |
| |
| /// The type defined by this typedef with `dynamic` as its type arguments. |
| /// |
| /// For instance `F<dynamic>` for `typedef void F<T>(T t)`. |
| ResolutionTypedefType get rawType; |
| |
| /// The type, function type if well-defined, for which this typedef is an |
| /// alias. |
| /// |
| /// For instance `(int)->void` for `typedef void F(int)`. |
| ResolutionDartType get alias; |
| |
| void checkCyclicReference(Resolution resolution); |
| } |
| |
| /// An executable element is an element that can hold code. |
| /// |
| /// These elements variables (fields, parameters and locals), which can hold |
| /// code in their initializer, and functions (including methods and |
| /// constructors), which can hold code in their body. |
| abstract class ExecutableElement extends Element |
| implements TypedElement, AstElement { |
| /// The outermost member that contains this element. |
| /// |
| /// For top level, static or instance members, the member context is the |
| /// element itself. For parameters, local variables and nested closures, the |
| /// member context is the top level, static or instance member in which it is |
| /// defined. |
| MemberElement get memberContext; |
| } |
| |
| /// A top-level, static or instance field or method, or a constructor. |
| /// |
| /// A [MemberElement] is the outermost executable element for any executable |
| /// context. |
| abstract class MemberElement extends Element |
| implements ExecutableElement, MemberEntity { |
| /// The local functions defined within this member. |
| List<MethodElement> get nestedClosures; |
| |
| /// The name of this member, taking privacy into account. |
| Name get memberName; |
| } |
| |
| /// A local function, variable, parameter or synthesized local. |
| abstract class LocalVariable implements Local { |
| /// The context in which this local is defined. |
| ExecutableElement get executableContext; |
| |
| /// The outermost member that contains this element. |
| /// |
| /// For top level, static or instance members, the member context is the |
| /// element itself. For parameters, local variables and nested closures, the |
| /// member context is the top level, static or instance member in which it is |
| /// defined. |
| MemberElement get memberContext; |
| } |
| |
| /// A function, variable or parameter defined in an executable context. |
| abstract class LocalElement extends Element |
| implements AstElement, TypedElement, LocalVariable { |
| ExecutableElement get executableContext; |
| } |
| |
| /// A top level, static or instance field, a formal parameter or local variable. |
| abstract class VariableElement extends ExecutableElement { |
| @override |
| VariableDefinitions get node; |
| |
| Expression get initializer; |
| |
| bool get hasConstant; |
| |
| /// The constant expression defining the (initial) value of the variable. |
| /// |
| /// If the variable is `const` the value is always non-null, possibly an |
| /// [ErroneousConstantExpression], otherwise, the value is null when the |
| /// initializer isn't a constant expression. |
| ConstantExpression get constant; |
| } |
| |
| /// A variable or parameter that is local to an executable context. |
| /// |
| /// The executable context is the [ExecutableElement] in which this variable |
| /// is defined. |
| abstract class LocalVariableElement extends VariableElement |
| implements LocalElement {} |
| |
| /// A top-level, static or instance field. |
| abstract class FieldElement extends VariableElement |
| implements MemberElement, FieldEntity {} |
| |
| /// A parameter-like element of a function signature. |
| /// |
| /// If the function signature comes from a typedef or an inline function-typed |
| /// parameter (e.g. the parameter 'f' in `method(void f())`), then its |
| /// parameters are not real parameters in that they can take no argument and |
| /// hold no value. Such parameter-like elements are modeled by [FormalElement]. |
| /// |
| /// If the function signature comes from a function or constructor, its |
| /// parameters are real parameters and are modeled by [ParameterElement]. |
| abstract class FormalElement extends Element |
| implements FunctionTypedElement, TypedElement, AstElement { |
| /// Use [functionDeclaration] instead. |
| @deprecated |
| get enclosingElement; |
| |
| /// The function, typedef or inline function-typed parameter on which |
| /// this parameter is declared. |
| FunctionTypedElement get functionDeclaration; |
| |
| VariableDefinitions get node; |
| |
| /// Whether the parameter is unnamed in a function type. |
| bool get isUnnamed; |
| } |
| |
| /// A formal parameter of a function or constructor. |
| /// |
| /// Normal parameter that introduce a local variable are modeled by |
| /// [LocalParameterElement] whereas initializing formals, that is parameter of |
| /// the form `this.x`, are modeled by [InitializingFormalElement]. |
| abstract class ParameterElement extends Element |
| implements VariableElement, FormalElement, LocalElement { |
| /// Use [functionDeclaration] instead. |
| @deprecated |
| get enclosingElement; |
| |
| /// The function on which this parameter is declared. |
| FunctionElement get functionDeclaration; |
| |
| /// `true` if this parameter is named. |
| bool get isNamed; |
| |
| /// `true` if this parameter is optional. |
| bool get isOptional; |
| } |
| |
| /// A formal parameter on a function or constructor that introduces a local |
| /// variable in the scope of the function or constructor. |
| abstract class LocalParameterElement extends ParameterElement |
| implements LocalVariableElement {} |
| |
| /// A formal parameter in a constructor that directly initializes a field. |
| /// |
| /// For example: `A(this.field)`. |
| abstract class InitializingFormalElement extends LocalParameterElement { |
| /// The field initialized by this initializing formal. |
| FieldElement get fieldElement; |
| |
| /// The function on which this parameter is declared. |
| ConstructorElement get functionDeclaration; |
| } |
| |
| /** |
| * A synthetic element which holds a getter and/or a setter. |
| * |
| * This element unifies handling of fields and getters/setters. When |
| * looking at code like "foo.x", we don't have to look for both a |
| * field named "x", a getter named "x", and a setter named "x=". |
| */ |
| abstract class AbstractFieldElement extends Element { |
| GetterElement get getter; |
| SetterElement get setter; |
| } |
| |
| abstract class FunctionSignature { |
| ResolutionFunctionType get type; |
| ResolutionDartType get returnType; |
| List<ResolutionDartType> get typeVariables; |
| List<FormalElement> get requiredParameters; |
| List<FormalElement> get optionalParameters; |
| |
| int get requiredParameterCount; |
| int get optionalParameterCount; |
| bool get optionalParametersAreNamed; |
| bool get hasOptionalParameters; |
| |
| int get parameterCount; |
| List<FormalElement> get orderedOptionalParameters; |
| |
| void forEachParameter(void function(FormalElement parameter)); |
| void forEachRequiredParameter(void function(FormalElement parameter)); |
| void forEachOptionalParameter(void function(FormalElement parameter)); |
| |
| void orderedForEachParameter(void function(FormalElement parameter)); |
| |
| bool isCompatibleWith(FunctionSignature constructorSignature); |
| |
| ParameterStructure get parameterStructure; |
| } |
| |
| /// A top level, static or instance method, constructor, local function, or |
| /// closure (anonymous local function). |
| abstract class FunctionElement extends Element |
| implements |
| AstElement, |
| TypedElement, |
| FunctionTypedElement, |
| ExecutableElement, |
| GenericElement { |
| FunctionExpression get node; |
| |
| FunctionElement get patch; |
| FunctionElement get origin; |
| |
| bool get hasFunctionSignature; |
| |
| /// The parameters of this function. |
| List<ParameterElement> get parameters; |
| |
| /// The type of this function. |
| ResolutionFunctionType get type; |
| |
| /// The synchronous/asynchronous marker on this function. |
| AsyncMarker get asyncMarker; |
| |
| /// `true` if this function is external. |
| /// |
| /// Patched methods are _not_ external, but [isMarkedExternal] is `true`. |
| bool get isExternal; |
| |
| /// `true` if this function is marked as external. |
| /// |
| /// If the function is implemented through a patch [isExternal] is `false`. |
| bool get isMarkedExternal; |
| |
| /// The structure of the function parameters. |
| ParameterStructure get parameterStructure; |
| } |
| |
| /// A getter or setter. |
| abstract class AccessorElement extends MethodElement { |
| /// Used to retrieve a link to the abstract field element representing this |
| /// element. |
| AbstractFieldElement get abstractField; |
| } |
| |
| /// A getter. |
| abstract class GetterElement extends AccessorElement { |
| /// The setter corresponding to this getter, if any. |
| SetterElement get setter; |
| } |
| |
| /// A setter. |
| abstract class SetterElement extends AccessorElement { |
| /// The getter corresponding to this setter, if any. |
| GetterElement get getter; |
| } |
| |
| /// A top level, static or instance function. |
| abstract class MethodElement extends FunctionElement |
| implements MemberElement, FunctionEntity {} |
| |
| /// A local function or closure (anonymous local function). |
| abstract class LocalFunctionElement extends FunctionElement |
| implements LocalElement { |
| /// The synthesized 'call' method created for this local function during |
| /// closure conversion. |
| MethodElement callMethod; |
| } |
| |
| /// A constructor. |
| abstract class ConstructorElement extends MethodElement |
| implements ConstructorEntity { |
| /// Returns `true` if [effectiveTarget] has been computed for this |
| /// constructor. |
| bool get hasEffectiveTarget; |
| |
| /// The effective target of this constructor, that is the non-redirecting |
| /// constructor that is called on invocation of this constructor. |
| /// |
| /// Consider for instance this hierarchy: |
| /// |
| /// class C { factory C.c() = D.d; } |
| /// class D { factory D.d() = E.e2; } |
| /// class E { E.e1(); |
| /// E.e2() : this.e1(); } |
| /// |
| /// The effective target of both `C.c`, `D.d`, and `E.e2` is `E.e2`, and the |
| /// effective target of `E.e1` is `E.e1` itself. |
| ConstructorElement get effectiveTarget; |
| |
| /// The immediate redirection target of a redirecting factory constructor. |
| /// |
| /// Consider for instance this hierarchy: |
| /// |
| /// class C { factory C() = D; } |
| /// class D { factory D() = E; } |
| /// class E { E(); } |
| /// |
| /// The immediate redirection target of `C` is `D` and the immediate |
| /// redirection target of `D` is `E`. `E` is not a redirecting factory |
| /// constructor so its immediate redirection target is `null`. |
| ConstructorElement get immediateRedirectionTarget; |
| |
| /// The prefix of the immediateRedirectionTarget, if it is deferred. |
| /// [null] if it is not deferred. |
| PrefixElement get redirectionDeferredPrefix; |
| |
| /// Is `true` if this constructor is a redirecting generative constructor. |
| bool get isRedirectingGenerative; |
| |
| /// Is `true` if this constructor is a redirecting factory constructor. |
| bool get isRedirectingFactory; |
| |
| /// Is `true` if this constructor is a redirecting factory constructor that is |
| /// part of a redirection cycle. |
| bool get isCyclicRedirection; |
| |
| /// Is `true` if the effective target of this constructor is malformed. |
| /// |
| /// A constructor is considered malformed if any of the following applies: |
| /// |
| /// * the constructor is undefined, |
| /// * the type of the constructor is undefined, |
| /// * the constructor is a redirecting factory and either |
| /// - it is part of a redirection cycle, |
| /// - the effective target is a generative constructor on an abstract |
| /// class, or |
| /// - this constructor is constant but the effective target is not, |
| /// - the arguments to this constructor are incompatible with the |
| /// parameters of the effective target. |
| bool get isEffectiveTargetMalformed; |
| |
| /// Compute the type of the effective target of this constructor for an |
| /// instantiation site with type [:newType:]. |
| /// May return a malformed type. |
| ResolutionDartType computeEffectiveTargetType( |
| ResolutionInterfaceType newType); |
| |
| /// If this is a synthesized constructor [definingConstructor] points to |
| /// the generative constructor from which this constructor was created. |
| /// Otherwise [definingConstructor] is `null`. |
| /// |
| /// Consider for instance this hierarchy: |
| /// |
| /// class C { C.c(a, {b}); |
| /// class D {} |
| /// class E = C with D; |
| /// |
| /// Class `E` has a synthesized constructor, `E.c`, whose defining constructor |
| /// is `C.c`. |
| ConstructorElement get definingConstructor; |
| |
| /// Returns `true` if this constructor is an implicit default constructor. |
| bool get isDefaultConstructor; |
| |
| /// The constant constructor defining the binding of fields if `const`, |
| /// `null` otherwise. |
| ConstantConstructor get constantConstructor; |
| |
| /// `true` if this constructor is one of `bool.fromEnvironment`, |
| /// `int.fromEnvironment`, or `String.fromEnvironment`. |
| bool get isFromEnvironmentConstructor; |
| |
| /// `true` if this constructor is `int.fromEnvironment`. |
| bool get isIntFromEnvironmentConstructor; |
| |
| /// `true` if this constructor is `bool.fromEnvironment`. |
| bool get isBoolFromEnvironmentConstructor; |
| |
| /// `true` if this constructor is `String.fromEnvironment`. |
| bool get isStringFromEnvironmentConstructor; |
| |
| /// Use [enclosingClass] instead. |
| @deprecated |
| get enclosingElement; |
| } |
| |
| /// JavaScript backend specific element for the body of constructor. |
| // TODO(johnniwinther): Remove this class from the element model. |
| abstract class ConstructorBodyElement extends MethodElement |
| implements ConstructorBodyEntity { |
| ConstructorElement get constructor; |
| } |
| |
| /// [GenericElement] defines the common interface for generic functions and |
| /// [TypeDeclarationElement]. |
| abstract class GenericElement extends Element implements AstElement { |
| /// Do not use [computeType] outside of the resolver. |
| /// |
| /// Trying to access a type that has not been computed in resolution is an |
| /// error and calling [computeType] covers that error. |
| /// This method will go away! |
| @deprecated |
| ResolutionDartType computeType(Resolution resolution); |
| |
| /** |
| * The type variables declared on this declaration. The type variables are not |
| * available until the type of the element has been computed through |
| * [computeType]. |
| */ |
| List<ResolutionDartType> get typeVariables; |
| } |
| |
| /// [TypeDeclarationElement] defines the common interface for class/interface |
| /// declarations and typedefs. |
| abstract class TypeDeclarationElement extends GenericElement { |
| /// The name of this type declaration, taking privacy into account. |
| Name get memberName; |
| |
| /// Do not use [computeType] outside of the resolver; instead retrieve the |
| /// type from the [thisType] or [rawType], depending on the use case. |
| /// |
| /// Trying to access a type that has not been computed in resolution is an |
| /// error and calling [computeType] covers that error. |
| /// This method will go away! |
| @deprecated |
| GenericType computeType(Resolution resolution); |
| |
| /** |
| * The `this type` for this type declaration. |
| * |
| * The type of [:this:] is the generic type based on this element in which |
| * the type arguments are the declared type variables. For instance, |
| * [:List<E>:] for [:List:] and [:Map<K,V>:] for [:Map:]. |
| * |
| * For a class declaration this is the type of [:this:]. |
| */ |
| GenericType get thisType; |
| |
| /** |
| * The raw type for this type declaration. |
| * |
| * The raw type is the generic type base on this element in which the type |
| * arguments are all [dynamic]. For instance [:List<dynamic>:] for [:List:] |
| * and [:Map<dynamic,dynamic>:] for [:Map:]. For non-generic classes [rawType] |
| * is the same as [thisType]. |
| * |
| * The [rawType] field is a canonicalization of the raw type and should be |
| * used to distinguish explicit and implicit uses of the [dynamic] |
| * type arguments. For instance should [:List:] be the [rawType] of the |
| * [:List:] class element whereas [:List<dynamic>:] should be its own |
| * instantiation of [ResolutionInterfaceType] with [:dynamic:] as type |
| * argument. Using this distinction, we can print the raw type with type |
| * arguments only when the input source has used explicit type arguments. |
| */ |
| GenericType get rawType; |
| |
| bool get isResolved; |
| |
| void ensureResolved(Resolution resolution); |
| } |
| |
| abstract class ClassElement extends TypeDeclarationElement |
| implements ScopeContainerElement, ClassEntity { |
| /// The length of the longest inheritance path from [:Object:]. |
| int get hierarchyDepth; |
| |
| ResolutionInterfaceType get rawType; |
| ResolutionInterfaceType get thisType; |
| ClassElement get superclass; |
| |
| /// The direct supertype of this class. |
| ResolutionDartType get supertype; |
| |
| /// Ordered set of all supertypes of this class including the class itself. |
| OrderedTypeSet get allSupertypesAndSelf; |
| |
| /// A list of all supertypes of this class excluding the class itself. |
| Link<InterfaceType> get allSupertypes; |
| |
| /// Returns the this type of this class as an instance of [cls]. |
| ResolutionInterfaceType asInstanceOf(ClassElement cls); |
| |
| /// A list of all direct superinterfaces of this class. |
| Link<ResolutionDartType> get interfaces; |
| |
| bool get hasConstructor; |
| Link<Element> get constructors; |
| |
| ClassElement get patch; |
| ClassElement get origin; |
| ClassElement get declaration; |
| ClassElement get implementation; |
| |
| /// `true` if this class is an enum declaration. |
| bool get isEnumClass; |
| |
| /// `true` if this class is a mixin application, either named or unnamed. |
| bool get isMixinApplication; |
| |
| /// `true` if this class is a named mixin application, e.g. |
| /// |
| /// class NamedMixinApplication = SuperClass with MixinClass; |
| /// |
| bool get isNamedMixinApplication; |
| |
| /// `true` if this class is an unnamed mixin application, e.g. the synthesized |
| /// `SuperClass+MixinClass` mixin application class in: |
| /// |
| /// class Class extends SuperClass with MixinClass {} |
| /// |
| bool get isUnnamedMixinApplication; |
| |
| bool get hasConstructorBodies; |
| bool get hasLocalScopeMembers; |
| |
| /// Returns `true` if this class is `Object` from dart:core. |
| bool get isObject; |
| |
| /// Returns `true` if this class implements [Function] either by directly |
| /// implementing the interface or by providing a [call] method. |
| bool implementsFunction(CommonElements commonElements); |
| |
| /// Returns `true` if this class extends [cls] directly or indirectly. |
| /// |
| /// This method is not to be used for checking type hierarchy and assignments, |
| /// because it does not take parameterized types into account. |
| bool isSubclassOf(ClassElement cls); |
| |
| /// Returns `true` if this class explicitly implements [intrface]. |
| /// |
| /// Note that, if [intrface] is the `Function` class, this method returns |
| /// false for a class that has a `call` method but does not explicitly |
| /// implement `Function`. |
| bool implementsInterface(ClassElement intrface); |
| |
| bool hasFieldShadowedBy(FieldElement fieldMember); |
| |
| /// Returns `true` if this class has a @proxy annotation. |
| bool get isProxy; |
| |
| /// Returns `true` if the class hierarchy for this class contains errors. |
| bool get hasIncompleteHierarchy; |
| |
| void addConstructorBody(ConstructorBodyElement element); |
| |
| Element lookupMember(String memberName); |
| |
| /// Looks up a class instance member declared or inherited in this class |
| /// using [memberName] to match the (private) name and getter/setter property. |
| /// |
| /// This method recursively visits superclasses until the member is found or |
| /// [stopAt] is reached. |
| MemberElement lookupByName(Name memberName, {ClassElement stopAt}); |
| MemberElement lookupSuperByName(Name memberName); |
| |
| Element lookupLocalMember(String memberName); |
| ConstructorBodyElement lookupConstructorBody(String memberName); |
| Element lookupSuperMember(String memberName); |
| |
| Element lookupSuperMemberInLibrary(String memberName, LibraryElement library); |
| |
| // TODO(johnniwinther): Clean up semantics. Can the default constructor take |
| // optional arguments? Must it be resolved? |
| ConstructorElement lookupDefaultConstructor(); |
| ConstructorElement lookupConstructor(String name); |
| |
| void forEachMember(void f(ClassElement enclosingClass, Element member), |
| {bool includeBackendMembers: false, |
| bool includeSuperAndInjectedMembers: false}); |
| |
| void forEachInstanceField( |
| void f(ClassElement enclosingClass, FieldElement field), |
| {bool includeSuperAndInjectedMembers: false}); |
| |
| /// Similar to [forEachInstanceField] but visits static fields. |
| void forEachStaticField(void f(ClassElement enclosingClass, Element field)); |
| |
| void forEachConstructorBody(void f(ConstructorBodyElement member)); |
| |
| /// Looks up the member [name] in this class. |
| Member lookupClassMember(Name name); |
| |
| /// Calls [f] with each member of this class. |
| void forEachClassMember(f(Member member)); |
| |
| /// Looks up the member [name] in the interface of this class. |
| MemberSignature lookupInterfaceMember(Name name); |
| |
| /// Calls [f] with each member of the interface of this class. |
| void forEachInterfaceMember(f(MemberSignature member)); |
| |
| /// Returns the type of the 'call' method in the interface of this class, or |
| /// `null` if the interface has no 'call' method. |
| ResolutionFunctionType get callType; |
| } |
| |
| abstract class MixinApplicationElement extends ClassElement { |
| ClassElement get mixin; |
| ResolutionInterfaceType get mixinType; |
| |
| /// If this is an unnamed mixin application [subclass] is the subclass for |
| /// which this mixin application is created. |
| ClassElement get subclass; |
| } |
| |
| /// Enum declaration. |
| abstract class EnumClassElement extends ClassElement { |
| /// The static fields implied by the enum values. |
| List<EnumConstantElement> get enumValues; |
| } |
| |
| /// An enum constant value. |
| abstract class EnumConstantElement extends FieldElement { |
| /// The enum that declared this constant. |
| EnumClassElement get enclosingClass; |
| |
| /// The index of this constant within the values of the enum. |
| int get index; |
| } |
| |
| /// The [Element] for a type variable declaration on a generic class or typedef. |
| abstract class TypeVariableElement extends Element |
| implements AstElement, TypedElement, TypeVariableEntity { |
| /// The name of this type variable, taking privacy into account. |
| Name get memberName; |
| |
| /// Use [typeDeclaration] instead. |
| @deprecated |
| get enclosingElement; |
| |
| /// The class, typedef, function, method, or function typed parameter on |
| /// which this type variable is defined. |
| GenericElement get typeDeclaration; |
| |
| /// The index of this type variable within its type declaration. |
| int get index; |
| |
| /// The [type] defined by the type variable. |
| ResolutionTypeVariableType get type; |
| |
| /// The upper bound on the type variable. If not explicitly declared, this is |
| /// `Object`. |
| ResolutionDartType get bound; |
| } |
| |
| abstract class MetadataAnnotation implements Spannable { |
| /// The front-end constant of this metadata annotation. |
| ConstantExpression get constant; |
| Element get annotatedElement; |
| SourceSpan get sourcePosition; |
| |
| bool get hasNode; |
| Node get node; |
| |
| MetadataAnnotation ensureResolved(Resolution resolution); |
| } |
| |
| /// An [Element] that has a type. |
| abstract class TypedElement extends Element { |
| /// Do not use [computeType] outside of the resolver; instead retrieve the |
| /// type from [type] property. |
| /// |
| /// Trying to access a type that has not been computed in resolution is an |
| /// error and calling [computeType] covers that error. |
| /// This method will go away! |
| @deprecated |
| ResolutionDartType computeType(Resolution resolution); |
| |
| ResolutionDartType get type; |
| } |
| |
| /// An [Element] that can define a function type. |
| abstract class FunctionTypedElement extends Element implements GenericElement { |
| /// The function signature for the function type defined by this element, |
| /// if any. |
| FunctionSignature get functionSignature; |
| } |
| |
| /// An [Element] that holds a [TreeElements] mapping. |
| abstract class AnalyzableElement extends Element { |
| /// Return `true` if [treeElements] have been (partially) computed for this |
| /// element. |
| bool get hasTreeElements; |
| |
| /// Returns the [TreeElements] that hold the resolution information for the |
| /// AST nodes of this element. |
| TreeElements get treeElements; |
| } |
| |
| /// An [Element] that (potentially) has a node. |
| /// |
| /// Synthesized elements may return `null` from [node]. |
| abstract class AstElement extends AnalyzableElement { |
| /// `true` if [node] is available and non-null. |
| bool get hasNode; |
| |
| /// The AST node of this element. |
| Node get node; |
| |
| /// `true` if [resolvedAst] is available. |
| bool get hasResolvedAst; |
| |
| /// The defining AST node of this element with is corresponding |
| /// [TreeElements]. This is not available if [hasResolvedAst] is `false`. |
| ResolvedAst get resolvedAst; |
| } |
| |
| /// Enum values for different ways of defining semantics for an element. |
| enum ResolvedAstKind { |
| /// The semantics of the element is defined in terms of an AST with resolved |
| /// data mapped in [TreeElements]. |
| PARSED, |
| |
| /// The element is an implicit default constructor. No AST or [TreeElements] |
| /// are provided. |
| DEFAULT_CONSTRUCTOR, |
| |
| /// The element is an implicit forwarding constructor on a mixin application. |
| /// No AST or [TreeElements] are provided. |
| FORWARDING_CONSTRUCTOR, |
| |
| /// The element is the `loadLibrary` getter implicitly defined on a deferred |
| /// prefix. |
| DEFERRED_LOAD_LIBRARY, |
| } |
| |
| /// [ResolvedAst] contains info that define the semantics of an element. |
| abstract class ResolvedAst { |
| /// The element whose semantics is defined. |
| Element get element; |
| |
| /// The kind of semantics definition used for this object. |
| ResolvedAstKind get kind; |
| |
| /// The root AST node for the declaration of [element]. This only available if |
| /// [kind] is `ResolvedAstKind.PARSED`. |
| Node get node; |
| |
| /// The AST node for the 'body' of [element]. |
| /// |
| /// For functions and constructors this is the root AST node of the method |
| /// body, and for variables this is the root AST node of the initializer, if |
| /// available. |
| /// |
| /// This only available if [kind] is `ResolvedAstKind.PARSED`. |
| Node get body; |
| |
| /// The [TreeElements] containing the resolution data for [node]. This only |
| /// available of [kind] is `ResolvedAstKind.PARSED`. |
| TreeElements get elements; |
| |
| /// Returns the uri for the source file defining [node] and [body]. This |
| /// only available if [kind] is `ResolvedAstKind.PARSED`. |
| Uri get sourceUri; |
| } |
| |
| /// [ResolvedAst] implementation used for elements whose semantics is defined in |
| /// terms an AST and a [TreeElements]. |
| class ParsedResolvedAst implements ResolvedAst { |
| final Element element; |
| final Node node; |
| final Node body; |
| final TreeElements elements; |
| final Uri sourceUri; |
| |
| ParsedResolvedAst( |
| this.element, this.node, this.body, this.elements, this.sourceUri); |
| |
| ResolvedAstKind get kind => ResolvedAstKind.PARSED; |
| |
| String toString() => '$kind:$element:$node'; |
| } |
| |
| /// [ResolvedAst] implementation used for synthesized elements whose semantics |
| /// is not defined in terms an AST and a [TreeElements]. |
| class SynthesizedResolvedAst implements ResolvedAst { |
| final Element element; |
| final ResolvedAstKind kind; |
| |
| SynthesizedResolvedAst(this.element, this.kind); |
| |
| @override |
| TreeElements get elements { |
| throw new UnsupportedError('$this does not provide a TreeElements'); |
| } |
| |
| @override |
| Node get node { |
| throw new UnsupportedError('$this does not have a root AST node'); |
| } |
| |
| @override |
| Node get body { |
| throw new UnsupportedError('$this does not have a body AST node'); |
| } |
| |
| @override |
| Uri get sourceUri { |
| throw new UnsupportedError('$this does not have a source URI'); |
| } |
| |
| String toString() => '$kind:$element'; |
| } |
| |
| /// A [MemberSignature] is a member of an interface. |
| /// |
| /// A signature is either a method or a getter or setter, possibly implicitly |
| /// defined by a field declarations. Fields themselves are not members of an |
| /// interface. |
| /// |
| /// A [MemberSignature] may be defined by a member declaration or may be |
| /// synthetized from a set of declarations. |
| abstract class MemberSignature { |
| /// The name of this member. |
| Name get name; |
| |
| /// The type of the member when accessed. For getters and setters this is the |
| /// return type and argument type, respectively. For methods the type is the |
| /// [functionType] defined by the return type and parameters. |
| ResolutionDartType get type; |
| |
| /// The function type of the member. For a getter `Foo get foo` this is |
| /// `() -> Foo`, for a setter `void set foo(Foo _)` this is `(Foo) -> void`. |
| /// For methods the function type is defined by the return type and |
| /// parameters. |
| ResolutionFunctionType get functionType; |
| |
| /// Returns `true` if this member is a getter, possibly implicitly defined by a |
| /// field declaration. |
| bool get isGetter; |
| |
| /// Returns `true` if this member is a setter, possibly implicitly defined by a |
| /// field declaration. |
| bool get isSetter; |
| |
| /// Returns `true` if this member is a method, that is neither a getter nor |
| /// setter. |
| bool get isMethod; |
| |
| /// Returns an iterable of the declarations that define this member. |
| Iterable<Member> get declarations; |
| } |
| |
| /// A [Member] is a member of a class, that is either a method or a getter or |
| /// setter, possibly implicitly defined by a field declarations. Fields |
| /// themselves are not members of a class. |
| /// |
| /// A [Member] of a class also defines a signature which is a member of the |
| /// corresponding interface type. |
| /// |
| /// A [Member] is implicitly concrete. An abstract declaration only declares |
| /// a signature in the interface of its class. |
| /// |
| /// A [Member] is always declared by an [Element] which is accessibly through |
| /// the [element] getter. |
| abstract class Member extends MemberSignature { |
| /// The [Element] that declared this member, possibly implicitly in case of |
| /// a getter or setter defined by a field. |
| MemberElement get element; |
| |
| /// The instance of the class that declared this member. |
| /// |
| /// For instance: |
| /// class A<T> { T m() {} } |
| /// class B<S> extends A<S> {} |
| /// The declarer of `m` in `A` is `A<T>` whereas the declarer of `m` in `B` is |
| /// `A<S>`. |
| ResolutionInterfaceType get declarer; |
| |
| /// Returns `true` if this member is static. |
| bool get isStatic; |
| |
| /// Returns `true` if this member is a getter or setter implicitly declared |
| /// by a field. |
| bool get isDeclaredByField; |
| |
| /// Returns `true` if this member is abstract. |
| bool get isAbstract; |
| |
| /// If abstract, [implementation] points to the overridden concrete member, |
| /// if any. Otherwise [implementation] points to the member itself. |
| Member get implementation; |
| } |