Stop using linked nodes for constructors.
Change-Id: I4ea147e415f4d622db3209184f02c630b75d0ecf Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/200060 Reviewed-by: Brian Wilkerson <brianwilkerson@google.com> Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
committed by
commit-bot@chromium.org
parent
fc15991ba7
commit
ca005159ac
@@ -509,32 +509,6 @@ class ClassElementImpl extends AbstractClassElementImpl
|
||||
return _constructors;
|
||||
}
|
||||
|
||||
if (linkedNode != null) {
|
||||
var context = enclosingUnit.linkedContext!;
|
||||
var containerRef = reference!.getChild('@constructor');
|
||||
_constructors = context.getConstructors(linkedNode!).map((node) {
|
||||
var name = node.name?.name ?? '';
|
||||
var reference = containerRef.getChild(name);
|
||||
var element = node.declaredElement;
|
||||
element ??= ConstructorElementImpl.forLinkedNode(this, reference, node);
|
||||
return element;
|
||||
}).toList();
|
||||
|
||||
if (_constructors.isEmpty) {
|
||||
return _constructors = [
|
||||
ConstructorElementImpl.forLinkedNode(
|
||||
this,
|
||||
containerRef.getChild(''),
|
||||
null,
|
||||
)
|
||||
..isSynthetic = true
|
||||
..name = ''
|
||||
..nameOffset = -1
|
||||
.._constantInitializers = const [],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
if (_constructors.isEmpty) {
|
||||
var constructor = ConstructorElementImpl('', -1);
|
||||
constructor.isSynthetic = true;
|
||||
@@ -954,13 +928,17 @@ class ClassElementImpl extends AbstractClassElementImpl
|
||||
// substituting type parameters as appropriate.
|
||||
return constructorsToForward
|
||||
.map((ConstructorElement superclassConstructor) {
|
||||
var containerRef = reference!.getChild('@constructor');
|
||||
var name = superclassConstructor.name;
|
||||
var implicitConstructor = ConstructorElementImpl.forLinkedNode(
|
||||
this, containerRef.getChild(name), null);
|
||||
var implicitConstructor = ConstructorElementImpl(name, -1);
|
||||
implicitConstructor.isSynthetic = true;
|
||||
implicitConstructor.name = name;
|
||||
implicitConstructor.nameOffset = -1;
|
||||
|
||||
var containerRef = reference!.getChild('@constructor');
|
||||
var implicitReference = containerRef.getChild(name);
|
||||
implicitConstructor.reference = implicitReference;
|
||||
implicitReference.element = implicitConstructor;
|
||||
|
||||
var hasMixinWithInstanceVariables = mixins.any(typeHasInstanceVariables);
|
||||
implicitConstructor.isConst =
|
||||
superclassConstructor.isConst && !hasMixinWithInstanceVariables;
|
||||
@@ -1639,15 +1617,13 @@ class ConstructorElementImpl extends ExecutableElementImpl
|
||||
|
||||
/// The initializers for this constructor (used for evaluating constant
|
||||
/// instance creation expressions).
|
||||
List<ConstructorInitializer> _constantInitializers =
|
||||
_Sentinel.constructorInitializer;
|
||||
List<ConstructorInitializer> _constantInitializers = const [];
|
||||
|
||||
/// The offset of the `.` before this constructor name or `null` if not named.
|
||||
int? _periodOffset;
|
||||
@override
|
||||
int? periodOffset;
|
||||
|
||||
/// Return the offset of the character immediately following the last
|
||||
/// character of this constructor's name, or `null` if not named.
|
||||
int? _nameEnd;
|
||||
@override
|
||||
int? nameEnd;
|
||||
|
||||
/// For every constructor we initially set this flag to `true`, and then
|
||||
/// set it to `false` during computing constant values if we detect that it
|
||||
@@ -1661,26 +1637,10 @@ class ConstructorElementImpl extends ExecutableElementImpl
|
||||
/// and [offset].
|
||||
ConstructorElementImpl(String name, int offset) : super(name, offset);
|
||||
|
||||
ConstructorElementImpl.forLinkedNode(ClassElementImpl enclosingClass,
|
||||
Reference reference, ConstructorDeclarationImpl? linkedNode)
|
||||
: super.forLinkedNode(enclosingClass, reference, linkedNode) {
|
||||
linkedNode?.declaredElement = this;
|
||||
}
|
||||
|
||||
/// Return the constant initializers for this element, which will be empty if
|
||||
/// there are no initializers, or `null` if there was an error in the source.
|
||||
List<ConstructorInitializer> get constantInitializers {
|
||||
linkedData?.read(this);
|
||||
if (!identical(_constantInitializers, _Sentinel.constructorInitializer)) {
|
||||
return _constantInitializers;
|
||||
}
|
||||
|
||||
if (linkedNode != null) {
|
||||
return _constantInitializers = linkedContext!.getConstructorInitializers(
|
||||
linkedNode as ConstructorDeclaration,
|
||||
);
|
||||
}
|
||||
|
||||
return _constantInitializers;
|
||||
}
|
||||
|
||||
@@ -1698,9 +1658,6 @@ class ConstructorElementImpl extends ExecutableElementImpl
|
||||
return linkedData.reference.name;
|
||||
}
|
||||
|
||||
if (linkedNode != null) {
|
||||
return reference!.name;
|
||||
}
|
||||
return super.displayName;
|
||||
}
|
||||
|
||||
@@ -1710,10 +1667,6 @@ class ConstructorElementImpl extends ExecutableElementImpl
|
||||
|
||||
@override
|
||||
bool get isConst {
|
||||
if (linkedNode != null) {
|
||||
final linkedNode = this.linkedNode as ConstructorDeclaration;
|
||||
return linkedNode.constKeyword != null;
|
||||
}
|
||||
return hasModifier(Modifier.CONST);
|
||||
}
|
||||
|
||||
@@ -1734,10 +1687,6 @@ class ConstructorElementImpl extends ExecutableElementImpl
|
||||
|
||||
@override
|
||||
bool get isFactory {
|
||||
if (linkedNode != null) {
|
||||
final linkedNode = this.linkedNode as ConstructorDeclaration;
|
||||
return linkedNode.factoryKeyword != null;
|
||||
}
|
||||
return hasModifier(Modifier.FACTORY);
|
||||
}
|
||||
|
||||
@@ -1752,61 +1701,9 @@ class ConstructorElementImpl extends ExecutableElementImpl
|
||||
@override
|
||||
ElementKind get kind => ElementKind.CONSTRUCTOR;
|
||||
|
||||
@override
|
||||
int? get nameEnd {
|
||||
if (linkedNode != null) {
|
||||
var node = linkedNode as ConstructorDeclaration;
|
||||
if (node.name != null) {
|
||||
return node.name!.end;
|
||||
} else {
|
||||
return node.returnType.end;
|
||||
}
|
||||
}
|
||||
|
||||
return _nameEnd;
|
||||
}
|
||||
|
||||
set nameEnd(int? nameEnd) {
|
||||
_nameEnd = nameEnd;
|
||||
}
|
||||
|
||||
@override
|
||||
int? get periodOffset {
|
||||
if (linkedNode != null) {
|
||||
var node = linkedNode as ConstructorDeclaration;
|
||||
return node.period?.offset;
|
||||
}
|
||||
|
||||
return _periodOffset;
|
||||
}
|
||||
|
||||
set periodOffset(int? periodOffset) {
|
||||
_periodOffset = periodOffset;
|
||||
}
|
||||
|
||||
@override
|
||||
ConstructorElement? get redirectedConstructor {
|
||||
linkedData?.read(this);
|
||||
if (_redirectedConstructor != null) return _redirectedConstructor;
|
||||
|
||||
if (linkedNode != null) {
|
||||
var context = enclosingUnit.linkedContext!;
|
||||
if (isFactory) {
|
||||
var node = context
|
||||
.getConstructorRedirected(linkedNode as ConstructorDeclaration);
|
||||
return _redirectedConstructor = node?.staticElement;
|
||||
} else {
|
||||
var initializers = context
|
||||
.getConstructorInitializers(linkedNode as ConstructorDeclaration);
|
||||
for (var initializer in initializers) {
|
||||
if (initializer is RedirectingConstructorInvocation) {
|
||||
return _redirectedConstructor = initializer.staticElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return _redirectedConstructor;
|
||||
}
|
||||
|
||||
@@ -6821,8 +6718,6 @@ class _Sentinel {
|
||||
static final List<ClassElement> classElement = List.unmodifiable([]);
|
||||
static final List<ConstructorElement> constructorElement =
|
||||
List.unmodifiable([]);
|
||||
static final List<ConstructorInitializer> constructorInitializer =
|
||||
List.unmodifiable([]);
|
||||
static final List<ElementAnnotation> elementAnnotation =
|
||||
List.unmodifiable([]);
|
||||
static final List<ExportElement> exportElement = List.unmodifiable([]);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
// 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/element/element.dart';
|
||||
import 'package:analyzer/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/dart/ast/ast.dart';
|
||||
import 'package:analyzer/src/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/element/scope.dart';
|
||||
@@ -14,47 +14,55 @@ class ConstructorInitializerResolver {
|
||||
final Linker _linker;
|
||||
final LibraryElementImpl _libraryElement;
|
||||
|
||||
late CompilationUnitElementImpl _unitElement;
|
||||
late ClassElement _classElement;
|
||||
late ConstructorElement _constructorElement;
|
||||
late ConstructorDeclarationImpl _constructorNode;
|
||||
late AstResolver _astResolver;
|
||||
|
||||
ConstructorInitializerResolver(this._linker, this._libraryElement);
|
||||
|
||||
void resolve() {
|
||||
for (var unit in _libraryElement.units) {
|
||||
_unitElement = unit as CompilationUnitElementImpl;
|
||||
for (var classElement in unit.types) {
|
||||
_classElement = classElement;
|
||||
for (var unitElement in _libraryElement.units) {
|
||||
var classElements = [...unitElement.mixins, ...unitElement.types];
|
||||
for (var classElement in classElements) {
|
||||
for (var constructorElement in classElement.constructors) {
|
||||
_constructor(constructorElement as ConstructorElementImpl);
|
||||
_constructor(
|
||||
unitElement as CompilationUnitElementImpl,
|
||||
classElement as ClassElementImpl,
|
||||
constructorElement as ConstructorElementImpl,
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _constructor(ConstructorElementImpl constructorElement) {
|
||||
if (constructorElement.isSynthetic) return;
|
||||
void _constructor(
|
||||
CompilationUnitElementImpl unitElement,
|
||||
ClassElementImpl classElement,
|
||||
ConstructorElementImpl element,
|
||||
) {
|
||||
if (element.isSynthetic) return;
|
||||
|
||||
_constructorElement = constructorElement;
|
||||
_constructorNode =
|
||||
constructorElement.linkedNode as ConstructorDeclarationImpl;
|
||||
var node = _linker.getLinkingNode(element) as ConstructorDeclarationImpl;
|
||||
|
||||
var functionScope = LinkingNodeContext.get(_constructorNode).scope;
|
||||
var functionScope = LinkingNodeContext.get(node).scope;
|
||||
var initializerScope = ConstructorInitializerScope(
|
||||
functionScope,
|
||||
constructorElement,
|
||||
element,
|
||||
);
|
||||
|
||||
_astResolver = AstResolver(
|
||||
_linker, _unitElement, initializerScope, _constructorNode,
|
||||
enclosingClassElement: _classElement,
|
||||
enclosingExecutableElement: _constructorElement);
|
||||
var astResolver = AstResolver(_linker, unitElement, initializerScope, node,
|
||||
enclosingClassElement: classElement,
|
||||
enclosingExecutableElement: element);
|
||||
|
||||
var body = _constructorNode.body;
|
||||
var body = node.body;
|
||||
body.localVariableInfo = LocalVariableInfo();
|
||||
|
||||
_astResolver.resolveConstructorNode(_constructorNode);
|
||||
astResolver.resolveConstructorNode(node);
|
||||
|
||||
if (node.factoryKeyword != null) {
|
||||
element.redirectedConstructor = node.redirectedConstructor?.staticElement;
|
||||
} else {
|
||||
for (var initializer in node.initializers) {
|
||||
if (initializer is RedirectingConstructorInvocation) {
|
||||
element.redirectedConstructor = initializer.staticElement;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,6 +77,33 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
|
||||
_buildClassOrMixin(node);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitConstructorDeclaration(
|
||||
covariant ConstructorDeclarationImpl node,
|
||||
) {
|
||||
var nameNode = node.name;
|
||||
var name = nameNode?.name ?? '';
|
||||
var nameOffset = nameNode?.offset ?? -1;
|
||||
|
||||
var element = ConstructorElementImpl(name, nameOffset);
|
||||
element.constantInitializers = node.initializers;
|
||||
element.isConst = node.constKeyword != null;
|
||||
element.isExternal = node.externalKeyword != null;
|
||||
element.isFactory = node.factoryKeyword != null;
|
||||
element.metadata = _buildAnnotations(node.metadata);
|
||||
_setCodeRange(element, node);
|
||||
|
||||
node.declaredElement = element;
|
||||
_linker.elementNodes[element] = node;
|
||||
|
||||
var reference = _enclosingContext.addConstructor(name, element);
|
||||
_buildExecutableElementChildren(
|
||||
reference: reference,
|
||||
element: element,
|
||||
formalParameters: node.parameters,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void visitDefaultFormalParameter(DefaultFormalParameter node) {
|
||||
node.parameter.accept(this);
|
||||
@@ -186,18 +213,19 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
|
||||
element = DefaultFieldFormalParameterElementImpl(name, nameOffset)
|
||||
..constantInitializer = parent.defaultValue;
|
||||
_linker.elementNodes[element] = parent;
|
||||
_enclosingContext.addParameter(name, element);
|
||||
} else {
|
||||
element = FieldFormalParameterElementImpl(name, nameOffset);
|
||||
_linker.elementNodes[element] = node;
|
||||
_enclosingContext.addParameter(null, element);
|
||||
}
|
||||
element.hasImplicitType = node.type == null;
|
||||
element.hasImplicitType = node.type == null && node.parameters == null;
|
||||
element.isExplicitlyCovariant = node.covariantKeyword != null;
|
||||
element.isFinal = node.isFinal;
|
||||
element.metadata = _buildAnnotations(node.metadata);
|
||||
element.parameterKind = node.kind;
|
||||
_setCodeRange(element, node);
|
||||
|
||||
_enclosingContext.addParameter(element.name, element);
|
||||
nameNode.staticElement = element;
|
||||
|
||||
var fakeReference = Reference.root();
|
||||
@@ -445,11 +473,12 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
|
||||
element = DefaultParameterElementImpl(name, nameOffset)
|
||||
..constantInitializer = parent.defaultValue;
|
||||
_linker.elementNodes[element] = parent;
|
||||
_enclosingContext.addParameter(name, element);
|
||||
} else {
|
||||
element = ParameterElementImpl(name, nameOffset);
|
||||
_linker.elementNodes[element] = node;
|
||||
_enclosingContext.addParameter(null, element);
|
||||
}
|
||||
_enclosingContext.addParameter(element.name, element);
|
||||
|
||||
element.hasImplicitType = node.type == null;
|
||||
element.isConst = node.isConst;
|
||||
@@ -537,19 +566,14 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
|
||||
}
|
||||
|
||||
_EnclosingContext _buildClassMembers(
|
||||
ElementImpl element, List<ClassMember> members) {
|
||||
ElementImpl element, NodeList<ClassMember> members) {
|
||||
var hasConstConstructor = members.any((e) {
|
||||
return e is ConstructorDeclaration && e.constKeyword != null;
|
||||
});
|
||||
var holder = _EnclosingContext(element.reference!, element,
|
||||
hasConstConstructor: hasConstConstructor);
|
||||
_withEnclosing(holder, () {
|
||||
// TODO(scheglov) build all members
|
||||
for (var member in members) {
|
||||
if (member is FieldDeclaration || member is MethodDeclaration) {
|
||||
member.accept(this);
|
||||
}
|
||||
}
|
||||
members.accept(this);
|
||||
});
|
||||
return holder;
|
||||
}
|
||||
@@ -560,6 +584,27 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
|
||||
element.accessors = holder.propertyAccessors;
|
||||
element.fields = holder.properties.whereType<FieldElement>().toList();
|
||||
element.methods = holder.methods;
|
||||
|
||||
var constructors = holder.constructors;
|
||||
if (constructors.isEmpty) {
|
||||
var containerRef = element.reference!.getChild('@constructor');
|
||||
constructors = [
|
||||
ConstructorElementImpl('', -1)
|
||||
..isSynthetic = true
|
||||
..reference = containerRef.getChild(''),
|
||||
];
|
||||
}
|
||||
element.constructors = constructors;
|
||||
|
||||
// We have all fields and constructors.
|
||||
// Now we can resolve field formal parameters.
|
||||
for (var constructor in constructors) {
|
||||
for (var parameter in constructor.parameters) {
|
||||
if (parameter is FieldFormalParameterElementImpl) {
|
||||
parameter.field = element.getField(parameter.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _buildExecutableElementChildren({
|
||||
@@ -766,6 +811,7 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
|
||||
class _EnclosingContext {
|
||||
final Reference reference;
|
||||
final ElementImpl element;
|
||||
final List<ConstructorElementImpl> constructors = [];
|
||||
final List<EnumElementImpl> enums = [];
|
||||
final List<FunctionElementImpl> functions = [];
|
||||
final List<MethodElementImpl> methods = [];
|
||||
@@ -781,6 +827,11 @@ class _EnclosingContext {
|
||||
this.hasConstConstructor = false,
|
||||
});
|
||||
|
||||
Reference addConstructor(String name, ConstructorElementImpl element) {
|
||||
constructors.add(element);
|
||||
return _bindReference('@constructor', name, element);
|
||||
}
|
||||
|
||||
Reference addEnum(String name, EnumElementImpl element) {
|
||||
enums.add(element);
|
||||
return _bindReference('@enum', name, element);
|
||||
|
||||
@@ -140,9 +140,10 @@ class _ConstructorInferenceNode extends _InferenceNode {
|
||||
this._constructor,
|
||||
Map<String, FieldElement> fieldMap,
|
||||
) {
|
||||
// TODO(scheglov) Can we rewrite this to just elements?
|
||||
for (var parameterElement in _constructor.parameters) {
|
||||
if (parameterElement is FieldFormalParameterElement) {
|
||||
var parameterNode = _getLinkedNode(parameterElement);
|
||||
var parameterNode = _walker._linker.getLinkingNode(parameterElement);
|
||||
if (parameterNode is DefaultFormalParameter) {
|
||||
parameterNode = parameterNode.parameter;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
|
||||
import 'package:analyzer/dart/element/element.dart';
|
||||
import 'package:analyzer/src/dart/error/syntactic_errors.dart';
|
||||
import 'package:analyzer/src/error/codes.dart';
|
||||
import 'package:test_reflective_loader/test_reflective_loader.dart';
|
||||
|
||||
import '../dart/resolution/context_collection_resolution.dart';
|
||||
@@ -25,9 +24,6 @@ mixin M {
|
||||
}
|
||||
''', [
|
||||
error(ParserErrorCode.MIXIN_DECLARES_CONSTRUCTOR, 27, 1),
|
||||
// TODO(srawlins): Don't report this from within a mixin.
|
||||
error(
|
||||
CompileTimeErrorCode.FIELD_INITIALIZING_FORMAL_NOT_ASSIGNABLE, 29, 6),
|
||||
]);
|
||||
|
||||
var element = findElement.mixin('M');
|
||||
|
||||
Reference in New Issue
Block a user