blob: 2c241ad24af293ceb23ecea2789816a2af9737d1 [file] [log] [blame]
// Copyright (c) 2019, 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/src/dart/element/element.dart';
import 'package:analyzer/src/summary2/link.dart';
class TypeAliasSelfReferenceFinder {
/// Check typedefs and mark the ones having self references.
void perform(Linker linker) {
for (var builder in linker.builders.values) {
for (var linkingUnit in builder.units) {
for (var node in linkingUnit.node.declarations) {
if (node is FunctionTypeAlias) {
var finder = _Finder(linker, node);
finder.functionTypeAlias(node);
var element = node.declaredElement as TypeAliasElementImpl;
element.hasSelfReference = finder.hasSelfReference;
} else if (node is GenericTypeAlias) {
var finder = _Finder(linker, node);
finder.genericTypeAlias(node);
var element = node.declaredElement as TypeAliasElementImpl;
element.hasSelfReference = finder.hasSelfReference;
}
}
}
}
}
}
class _Finder {
final Linker linker;
final AstNode self;
final Set<AstNode> visited = Set.identity();
bool hasSelfReference = false;
_Finder(this.linker, this.self);
void functionTypeAlias(FunctionTypeAlias node) {
_typeParameterList(node.typeParameters);
_formalParameterList(node.parameters);
_visit(node.returnType);
}
void genericTypeAlias(GenericTypeAlias node) {
_typeParameterList(node.typeParameters);
_visit(node.type);
}
void _argumentList(TypeArgumentList? node) {
if (node != null) {
for (var argument in node.arguments) {
_visit(argument);
}
}
}
void _formalParameter(FormalParameter node) {
if (node is DefaultFormalParameter) {
_formalParameter(node.parameter);
} else if (node is FunctionTypedFormalParameter) {
_visit(node.returnType);
_formalParameterList(node.parameters);
} else if (node is SimpleFormalParameter) {
_visit(node.type);
}
}
void _formalParameterList(FormalParameterList node) {
for (var parameter in node.parameters) {
_formalParameter(parameter);
}
}
void _typeParameterList(TypeParameterList? node) {
if (node != null) {
for (var parameter in node.typeParameters) {
_visit(parameter.bound);
}
}
}
void _visit(TypeAnnotation? node) {
if (hasSelfReference) return;
if (node == null) return;
if (node is NamedType) {
var element = node.name.staticElement;
if (element is! ElementImpl) {
return;
}
var typeNode = linker.getLinkingNode(element);
if (typeNode != null) {
if (typeNode == self) {
hasSelfReference = true;
return;
}
if (typeNode is ClassDeclaration) {
if (visited.add(typeNode)) {
_typeParameterList(typeNode.typeParameters);
}
} else if (typeNode is ClassTypeAlias) {
if (visited.add(typeNode)) {
_typeParameterList(typeNode.typeParameters);
}
} else if (typeNode is FunctionTypeAlias) {
if (visited.add(typeNode)) {
functionTypeAlias(typeNode);
}
} else if (typeNode is GenericTypeAlias) {
if (visited.add(typeNode)) {
genericTypeAlias(typeNode);
}
} else if (typeNode is MixinDeclaration) {
if (visited.add(typeNode)) {
_typeParameterList(typeNode.typeParameters);
}
}
}
_argumentList(node.typeArguments);
} else if (node is GenericFunctionType) {
_typeParameterList(node.typeParameters);
_formalParameterList(node.parameters);
_visit(node.returnType);
} else {
throw UnimplementedError('(${node.runtimeType}) $node');
}
}
}