| // Copyright (c) 2020, 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/analysis/features.dart'; | |
| import 'package:analyzer/dart/element/element.dart'; | |
| import 'package:analyzer/dart/element/nullability_suffix.dart'; | |
| import 'package:analyzer/dart/element/type.dart'; | |
| import 'package:analyzer/source/source.dart'; | |
| import 'package:analyzer/source/source_range.dart'; | |
| import 'package:analyzer/src/dart/element/element.dart'; | |
| import 'package:analyzer/src/dart/element/type.dart'; | |
| import 'package:analyzer/src/generated/utilities_dart.dart'; | |
| extension DartTypeExtension on DartType { | |
| bool get isExtensionType { | |
| return element is ExtensionTypeElement; | |
| } | |
| } | |
| extension Element2Extension on Element { | |
| /// Whether a reference to this element reads a constant variable, either | |
| /// the variable itself, or its implicit getter. | |
| bool get denotesConstantVariable { | |
| return switch (this) { | |
| PropertyAccessorElement(:var isOriginDeclaration, :var variable) => | |
| !isOriginDeclaration && variable.isConst, | |
| VariableElement(:var isConst) => isConst, | |
| _ => false, | |
| }; | |
| } | |
| TypeImpl? get firstParameterType { | |
| var self = this; | |
| if (self is InternalMethodElement) { | |
| return self.formalParameters.firstOrNull?.type; | |
| } | |
| return null; | |
| } | |
| /// Return `true` if this element, the enclosing class (if there is one), or | |
| /// the enclosing library, has been annotated with the `@doNotStore` | |
| /// annotation. | |
| bool get hasOrInheritsDoNotStore { | |
| if (metadata.hasDoNotStore) { | |
| return true; | |
| } | |
| var ancestor = enclosingElement; | |
| if (ancestor is InterfaceElement) { | |
| if (ancestor.metadata.hasDoNotStore) { | |
| return true; | |
| } | |
| ancestor = ancestor.enclosingElement; | |
| } else if (ancestor is ExtensionElement) { | |
| if (ancestor.metadata.hasDoNotStore) { | |
| return true; | |
| } | |
| ancestor = ancestor.enclosingElement; | |
| } | |
| return ancestor is LibraryElement && ancestor.metadata.hasDoNotStore; | |
| } | |
| /// Return `true` if this element is an instance member of a class or mixin. | |
| /// | |
| /// Only [MethodElement]s, [GetterElement]s, and [SetterElement]s are | |
| /// supported. | |
| /// | |
| /// We intentionally exclude [ConstructorElement]s - they can only be | |
| /// invoked in instance creation expressions, and [FieldElement]s - they | |
| /// cannot be invoked directly and are always accessed using corresponding | |
| /// [GetterElement]s or [SetterElement]s. | |
| bool get isInstanceMember { | |
| assert( | |
| this is! PropertyInducingElement, | |
| 'Check the GetterElement or SetterElement instead', | |
| ); | |
| var this_ = this; | |
| var enclosing = this_.enclosingElement; | |
| if (enclosing is InterfaceElement) { | |
| return this_ is MethodElement && !this_.isStatic || | |
| this_ is GetterElement && !this_.isStatic || | |
| this_ is SetterElement && !this_.isStatic; | |
| } | |
| return false; | |
| } | |
| /// Whether this element is a wildcard variable. | |
| bool get isWildcardVariable { | |
| return name == '_' && | |
| (this is LocalFunctionElement || | |
| this is LocalVariableElement || | |
| this is PrefixElement || | |
| this is TypeParameterElement || | |
| (this is FormalParameterElement && | |
| this is! FieldFormalParameterElement && | |
| this is! SuperFormalParameterElement)) && | |
| library.hasWildcardVariablesFeatureEnabled; | |
| } | |
| /// Computes a [SourceRange] suitable for reporting a diagnostic related to | |
| /// this element. | |
| /// | |
| /// Since [SourceRange] objects carry offset and length information but no | |
| /// filename information, the caller should make sure to only call this method | |
| /// on elements whose declaration appears in the particular compilation unit | |
| /// they are generating diagnostics for. To reduce the risk of mistakes, the | |
| /// caller is required to pass in the [Source] for which they are generating | |
| /// diagnostics; an assertion will fire if this doesn't match the source | |
| /// containing the element's first fragment. | |
| SourceRange diagnosticRange(Source source) { | |
| var nonSyntheticLocation = | |
| (nonSynthetic.baseElement as ElementImpl).firstFragmentLocation; | |
| // Note: sources are compared using `==` rather than `identical`, because | |
| // during an incremental update to the element model, elements that are | |
| // unchanged may still point to an older (but equivalent) `source` object. | |
| assert(nonSyntheticLocation.libraryFragment?.source == source); | |
| return SourceRange( | |
| nonSyntheticLocation.nameOffset ?? -1, | |
| nonSyntheticLocation.name?.length ?? 0, | |
| ); | |
| } | |
| } | |
| extension ExecutableElement2Extension on ExecutableElement { | |
| /// Whether the enclosing element is the class `Object`. | |
| bool get isObjectMember { | |
| var enclosing = enclosingElement; | |
| return enclosing is ClassElement && enclosing.isDartCoreObject; | |
| } | |
| } | |
| extension FormalParameterElementMixinExtension | |
| on InternalFormalParameterElement { | |
| /// Returns [FormalParameterElementImpl] with the specified properties | |
| /// replaced. | |
| FormalParameterElementImpl copyWith({ | |
| TypeImpl? type, | |
| ParameterKind? kind, | |
| bool? isCovariant, | |
| }) { | |
| var element = FormalParameterElementImpl.synthetic( | |
| name, | |
| type ?? this.type, | |
| kind ?? parameterKind, | |
| baseFormalParameter: baseElement, | |
| ); | |
| element.isCovariant = isCovariant ?? this.isCovariant; | |
| return element; | |
| } | |
| } | |
| extension InterfaceTypeExtension on InterfaceType { | |
| bool get isDartCoreObjectNone { | |
| return isDartCoreObject && nullabilitySuffix == NullabilitySuffix.none; | |
| } | |
| } | |
| extension LibraryExtension2 on LibraryElement? { | |
| bool get hasWildcardVariablesFeatureEnabled => | |
| this?.featureSet.isEnabled(Feature.wildcard_variables) ?? false; | |
| } | |
| extension RecordTypeExtension on RecordType { | |
| /// A regular expression used to match positional field names. | |
| static final RegExp _positionalName = RegExp(r'^\$[1-9]\d*$'); | |
| List<RecordTypeField> get fields { | |
| return [...positionalFields, ...namedFields]; | |
| } | |
| /// The [name] is either an actual name like `foo` in `({int foo})`, or | |
| /// the name of a positional field like `$1` in `(int, String)`. | |
| RecordTypeFieldImpl? fieldByName(String name) { | |
| return namedField(name) ?? positionalField(name); | |
| } | |
| RecordTypeNamedFieldImpl? namedField(String name) { | |
| for (var field in namedFields) { | |
| if (field.name == name) { | |
| // TODO(paulberry): eliminate this cast by changing the extension to | |
| // only apply to `RecordTypeImpl`. | |
| return field as RecordTypeNamedFieldImpl; | |
| } | |
| } | |
| return null; | |
| } | |
| RecordTypePositionalFieldImpl? positionalField(String name) { | |
| var index = positionalFieldIndex(name); | |
| if (index != null && index < positionalFields.length) { | |
| // TODO(paulberry): eliminate this cast by changing the extension to only | |
| // apply to `RecordTypeImpl`. | |
| return positionalFields[index] as RecordTypePositionalFieldImpl; | |
| } | |
| return null; | |
| } | |
| /// Attempt to parse `$1`, `$2`, etc. | |
| static int? positionalFieldIndex(String name) { | |
| if (_positionalName.hasMatch(name)) { | |
| var positionString = name.substring(1); | |
| // Use `tryParse` instead of `parse` | |
| // even though the numeral matches the pattern `[1-9]\d*`, | |
| // to reject numerals too big to fit in an `int`. | |
| var position = int.tryParse(positionString); | |
| if (position != null) return position - 1; | |
| } | |
| return null; | |
| } | |
| } | |
| extension TypeParameterElementImplExtension on TypeParameterElementImpl { | |
| bool get isWildcardVariable { | |
| return name == '_' && library.hasWildcardVariablesFeatureEnabled; | |
| } | |
| } |