blob: 3df6b5d9fd245fae2b30a382fa91a95b200a8803 [file] [log] [blame]
// 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/ast/ast.dart';
import 'package:analyzer/dart/element/element.dart';
import 'package:analyzer/dart/element/type.dart';
import 'package:analyzer/src/dart/ast/ast.dart';
/// TODO(scheglov) https://github.com/dart-lang/sdk/issues/43608
Element? _readElement(AstNode node) {
var parent = node.parent;
if (parent is AssignmentExpression && parent.leftHandSide == node) {
return parent.readElement;
}
if (parent is PostfixExpression && parent.operand == node) {
return parent.readElement;
}
if (parent is PrefixExpression && parent.operand == node) {
return parent.readElement;
}
if (parent is PrefixedIdentifier && parent.identifier == node) {
return _readElement(parent);
}
if (parent is PropertyAccess && parent.propertyName == node) {
return _readElement(parent);
}
return null;
}
/// TODO(scheglov) https://github.com/dart-lang/sdk/issues/43608
Element? _writeElement(AstNode node) {
var parent = node.parent;
if (parent is AssignmentExpression && parent.leftHandSide == node) {
return parent.writeElement;
}
if (parent is PostfixExpression && parent.operand == node) {
return parent.writeElement;
}
if (parent is PrefixExpression && parent.operand == node) {
return parent.writeElement;
}
if (parent is PrefixedIdentifier && parent.identifier == node) {
return _writeElement(parent);
}
if (parent is PropertyAccess && parent.propertyName == node) {
return _writeElement(parent);
}
return null;
}
/// TODO(scheglov) https://github.com/dart-lang/sdk/issues/43608
DartType? _writeType(AstNode node) {
var parent = node.parent;
if (parent is AssignmentExpression && parent.leftHandSide == node) {
return parent.writeType;
}
if (parent is PostfixExpression && parent.operand == node) {
return parent.writeType;
}
if (parent is PrefixExpression && parent.operand == node) {
return parent.writeType;
}
if (parent is PrefixedIdentifier && parent.identifier == node) {
return _writeType(parent);
}
if (parent is PropertyAccess && parent.propertyName == node) {
return _writeType(parent);
}
return null;
}
extension AstNodeNullableExtension on AstNode? {
List<ClassMember> get classMembers {
final self = this;
if (self is ClassOrMixinDeclaration) {
return self.members;
} else if (self is EnumDeclaration) {
return self.members;
} else if (self is ExtensionDeclaration) {
return self.members;
} else {
throw UnimplementedError('(${self.runtimeType}) $self');
}
}
}
extension ConstructorDeclarationExtension on ConstructorDeclaration {
bool get isNonRedirectingGenerative {
// Must be generative.
if (externalKeyword != null || factoryKeyword != null) {
return false;
}
// Must be non-redirecting.
for (var initializer in initializers) {
if (initializer is RedirectingConstructorInvocation) {
return false;
}
}
return true;
}
}
extension ExpressionExtension on Expression {
/// Return the static type of this expression.
///
/// This accessor should be used on expressions that are expected to
/// be already resolved. Every such expression must have the type set,
/// at least `dynamic`.
DartType get typeOrThrow {
var type = staticType;
if (type == null) {
throw StateError('No type: $this');
}
return type;
}
}
extension FormalParameterExtension on FormalParameter {
bool get isOfLocalFunction {
return thisOrAncestorOfType<FunctionBody>() != null;
}
FormalParameter get notDefault {
var self = this;
if (self is DefaultFormalParameter) {
return self.parameter;
}
return self;
}
FormalParameterList get parentFormalParameterList {
var parent = this.parent;
if (parent is DefaultFormalParameter) {
parent = parent.parent;
}
return parent as FormalParameterList;
}
AstNode get typeOrSelf {
var self = this;
if (self is SimpleFormalParameter) {
var type = self.type;
if (type != null) {
return type;
}
}
return self;
}
}
/// TODO(scheglov) https://github.com/dart-lang/sdk/issues/43608
extension IdentifierExtension on Identifier {
Element? get readElement {
return _readElement(this);
}
Element? get writeElement {
return _writeElement(this);
}
Element? get writeOrReadElement {
return _writeElement(this) ?? staticElement;
}
DartType? get writeOrReadType {
return _writeType(this) ?? staticType;
}
}
/// TODO(scheglov) https://github.com/dart-lang/sdk/issues/43608
extension IndexExpressionExtension on IndexExpression {
Element? get writeOrReadElement {
return _writeElement(this) ?? staticElement;
}
}
extension ListOfFormalParameterExtension on List<FormalParameter> {
Iterable<FormalParameterImpl> get asImpl {
return cast<FormalParameterImpl>();
}
}
extension TypeAnnotationExtension on TypeAnnotation {
/// Return the static type of this type annotation.
///
/// This accessor should be used on expressions that are expected to
/// be already resolved. Every such expression must have the type set,
/// at least `dynamic`.
DartType get typeOrThrow {
final type = this.type;
if (type == null) {
throw StateError('No type: $this');
}
return type;
}
}