Build ClassAugmentationElementImpl, basic linking.

Change-Id: I18bd3d97ad9fe661d14e3d3d006219ffceedcfc4
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/312349
Reviewed-by: Brian Wilkerson <brianwilkerson@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2023-07-07 14:55:38 +00:00 committed by Commit Queue
parent 9d876d12b2
commit fc0e656868
22 changed files with 543 additions and 132 deletions

View file

@ -55,7 +55,8 @@ class RedirectingContributor extends DartCompletionContributor {
var containingConstructor =
parent.thisOrAncestorOfType<ConstructorDeclaration>();
var constructorElement = containingConstructor?.declaredElement;
var classElement = constructorElement?.enclosingElement2;
var classElement =
constructorElement?.enclosingElement2.augmentedDeclaration;
var libraryElement = request.libraryElement;
if (classElement == null) {
return;

View file

@ -420,7 +420,12 @@ class SuggestionBuilder {
// If the class name is already in the text, then we don't support
// prepending a prefix.
assert(!hasClassName || prefix == null);
var enclosingClass = constructor.enclosingElement2;
var enclosingClass = constructor.enclosingElement2.augmentedDeclaration;
if (enclosingClass == null) {
return;
}
var className = enclosingClass.name;
if (className.isEmpty) {
return;
@ -828,7 +833,8 @@ class SuggestionBuilder {
var element = parameter.enclosingElement2;
// If appendColon is false, default values should never be appended.
if (element is ConstructorElement && appendColon) {
if (Flutter.instance.isWidget(element.enclosingElement2)) {
if (Flutter.instance
.isWidget(element.enclosingElement2.augmentedDeclaration)) {
var codeStyleOptions = request
.analysisSession.analysisContext.analysisOptions.codeStyleOptions;
// Don't bother with nullability. It won't affect default list values.

View file

@ -203,7 +203,8 @@ class Flutter {
/// Return the presentation for the given Flutter `Widget` creation [node].
String? getWidgetPresentationText(InstanceCreationExpression node) {
var element = node.constructorName.staticElement?.enclosingElement2;
var element = node
.constructorName.staticElement?.enclosingElement2.augmentedDeclaration;
if (!isWidget(element)) {
return null;
}
@ -524,7 +525,8 @@ class Flutter {
/// Return `true` if the given [expr] is a constructor invocation for a
/// class that has the Flutter class `Widget` as a superclass.
bool isWidgetCreation(InstanceCreationExpression? expr) {
var element = expr?.constructorName.staticElement?.enclosingElement2;
var element = expr
?.constructorName.staticElement?.enclosingElement2.augmentedDeclaration;
return isWidget(element);
}

View file

@ -212,7 +212,7 @@ abstract class ClassAugmentationElement implements ClassOrAugmentationElement {
///
/// Clients may not extend, implement or mix-in this class.
abstract class ClassElement
implements ClassOrAugmentationElement, InterfaceElement {
implements InterfaceElement, ClassOrAugmentationElement {
/// The result of applying augmentations.
AugmentedClassElement get augmented;
@ -343,6 +343,9 @@ abstract class ClassOrAugmentationElement
/// [ClassAugmentationElement.augmentationTarget] is the back pointer that
/// will point at this element.
ClassAugmentationElement? get augmentation;
@override
ClassElement? get augmentedDeclaration;
}
/// An element representing a compilation unit.
@ -353,6 +356,9 @@ abstract class CompilationUnitElement implements UriReferencedElement {
/// compilation unit.
List<PropertyAccessorElement> get accessors;
/// The class augmentations declared in this compilation unit.
List<ClassAugmentationElement> get classAugmentations;
/// The classes declared in this compilation unit.
List<ClassElement> get classes;
@ -439,7 +445,7 @@ abstract class ConstructorElement
InterfaceElement get enclosingElement;
@override
NamedInstanceElement get enclosingElement2;
NamedInstanceOrAugmentationElement get enclosingElement2;
/// Whether the constructor is a const constructor.
bool get isConst;
@ -477,7 +483,7 @@ abstract class ConstructorElement
InterfaceType get returnType;
@override
NamedInstanceType get returnType2;
DartType get returnType2;
}
/// [ImportElementPrefix] that is used together with `deferred`.
@ -1202,7 +1208,7 @@ abstract class EnumAugmentationElement implements EnumOrAugmentationElement {
///
/// Clients may not extend, implement or mix-in this class.
abstract class EnumElement
implements EnumOrAugmentationElement, InterfaceElement {
implements InterfaceElement, EnumOrAugmentationElement {
/// The result of applying augmentations.
AugmentedEnumElement get augmented;
}
@ -1219,6 +1225,9 @@ abstract class EnumOrAugmentationElement
/// [EnumAugmentationElement.augmentationTarget] is the back pointer that
/// will point at this element.
EnumAugmentationElement? get augmentation;
@override
EnumElement? get augmentedDeclaration;
}
/// An element representing an executable object, including functions, methods,
@ -1502,7 +1511,7 @@ abstract class InlineClassAugmentationElement
/// Clients may not extend, implement or mix-in this class.
@experimental
abstract class InlineClassElement
implements InlineClassOrAugmentationElement, NamedInstanceElement {
implements NamedInstanceElement, InlineClassOrAugmentationElement {
/// The result of applying augmentations.
@experimental
AugmentedInlineClassElement get augmented;
@ -1524,6 +1533,25 @@ abstract class InlineClassOrAugmentationElement
/// [InlineClassAugmentationElement.augmentationTarget] is the back pointer
/// that will point at this element.
InlineClassAugmentationElement? get augmentation;
@override
InlineClassElement? get augmentedDeclaration;
}
/// [InstanceElement] augmentation.
///
/// Clients may not extend, implement or mix-in this class.
@experimental
abstract class InstanceAugmentationElement
implements InstanceOrAugmentationElement {
/// The element that is augmented by this augmentation; or `null` if
/// there is no corresponding element to be augmented.
///
/// The chain of augmentations should normally end with a [InstanceElement],
/// but might end with `null` immediately or after a few intermediate
/// [InstanceAugmentationElement]s in case of invalid code when an
/// augmentation is declared without the corresponding declaration.
InstanceOrAugmentationElement? get augmentationTarget;
}
/// An element that has `this`.
@ -1550,6 +1578,11 @@ abstract class InstanceOrAugmentationElement
/// The declared accessors (getters and setters).
List<PropertyAccessorElement> get accessors;
/// The declaration in the main library, the start of the augmentation chain.
///
/// [InstanceElement] returns itself.
InstanceElement? get augmentedDeclaration;
@Deprecated('Use enclosingElement2 instead')
@override
CompilationUnitElement get enclosingElement;
@ -1568,7 +1601,7 @@ abstract class InstanceOrAugmentationElement
///
/// Clients may not extend, implement or mix-in this class.
abstract class InterfaceElement
implements InterfaceOrAugmentationElement, NamedInstanceElement {
implements NamedInstanceElement, InterfaceOrAugmentationElement {
/// All the supertypes defined for this element and its supertypes.
///
/// This includes superclasses, mixins, interfaces, and superclass constraints.
@ -1800,6 +1833,9 @@ abstract class InterfaceElement
@experimental
abstract class InterfaceOrAugmentationElement
implements NamedInstanceOrAugmentationElement {
@override
InterfaceElement? get augmentedDeclaration;
/// The interfaces that are implemented by this class.
///
/// <b>Note:</b> Because the element model represents the state of the code,
@ -2126,7 +2162,7 @@ abstract class MixinAugmentationElement implements MixinOrAugmentationElement {
///
/// Clients may not extend, implement or mix-in this class.
abstract class MixinElement
implements MixinOrAugmentationElement, InterfaceElement {
implements InterfaceElement, MixinOrAugmentationElement {
/// The result of applying augmentations.
AugmentedMixinElement get augmented;
@ -2166,6 +2202,9 @@ abstract class MixinOrAugmentationElement
/// [MixinAugmentationElement.augmentationTarget] is the back pointer that
/// will point at this element.
MixinAugmentationElement? get augmentation;
@override
MixinElement? get augmentedDeclaration;
}
/// A pseudo-element that represents multiple elements defined within a single
@ -2194,7 +2233,7 @@ abstract class MultiplyInheritedExecutableElement implements ExecutableElement {
/// Clients may not extend, implement or mix-in this class.
@experimental
abstract class NamedInstanceElement
implements NamedInstanceOrAugmentationElement, InstanceElement {
implements InstanceElement, NamedInstanceOrAugmentationElement {
/// Create the [DartType] for this element with the given [typeArguments]
/// and [nullabilitySuffix].
DartType instantiate({
@ -2209,6 +2248,9 @@ abstract class NamedInstanceElement
@experimental
abstract class NamedInstanceOrAugmentationElement
implements InstanceOrAugmentationElement {
@override
NamedInstanceElement? get augmentedDeclaration;
/// The declared constructors.
///
/// The list is empty for [MixinElement].

View file

@ -87,7 +87,7 @@ import 'package:analyzer/src/utilities/uri_cache.dart';
/// TODO(scheglov) Clean up the list of implicitly analyzed files.
class AnalysisDriver implements AnalysisDriverGeneric {
/// The version of data format, should be incremented on every format change.
static const int DATA_VERSION = 279;
static const int DATA_VERSION = 280;
/// The number of exception contexts allowed to write. Once this field is
/// zero, we stop writing any new exception contexts in this process.

View file

@ -2705,7 +2705,7 @@ final class ClassAugmentationDeclarationImpl
final Token augmentKeyword;
@override
ClassAugmentationElement? declaredElement;
ClassAugmentationElementImpl? declaredElement;
ClassAugmentationDeclarationImpl({
required super.comment,

View file

@ -248,12 +248,16 @@ class ConstantVerifier extends RecursiveAstVisitor<void> {
// evaluation.
var constructor = node.constructorName.staticElement;
if (constructor != null) {
var returnType = constructor.returnType2;
if (returnType is! InterfaceType) {
return;
}
ConstantVisitor constantVisitor =
ConstantVisitor(_evaluationEngine, _currentLibrary, _errorReporter);
_evaluationEngine.evaluateConstructorCall(
_currentLibrary,
node,
constructor.returnType2.typeArguments,
returnType.typeArguments,
node.argumentList.arguments,
constructor,
constantVisitor,

View file

@ -195,7 +195,7 @@ class ConstantEvaluationEngine {
var result = evaluateConstructorCall(
library,
constNode,
element.returnType2.typeArguments,
element.returnType2.ifTypeOrNull<InterfaceType>()?.typeArguments,
constNode.arguments!.arguments,
element,
constantVisitor,
@ -891,7 +891,7 @@ class ConstantVisitor extends UnifyingAstVisitor<Constant> {
return evaluationEngine.evaluateConstructorCall(
_library,
node,
constructor.returnType2.typeArguments,
constructor.returnType2.ifTypeOrNull<InterfaceType>()?.typeArguments,
node.argumentList.arguments,
constructor,
this,
@ -2432,7 +2432,9 @@ class _InstanceCreationEvaluator {
_argumentValues = argumentValues,
_invocation = invocation;
NamedInstanceType get definingType => _constructor.returnType2;
NamedInstanceType get definingType =>
_constructor.returnType2.ifTypeOrNull<InterfaceType>() ??
typeProvider.objectType;
DartObjectImpl? get firstArgument => _argumentValues[0];
@ -2572,7 +2574,7 @@ class _InstanceCreationEvaluator {
continue;
}
// Match the value and the type.
var fieldType = FieldMember.from(field, _constructor.returnType2).type;
var fieldType = FieldMember.from(field, definingType).type;
if (!typeSystem.runtimeTypeMatch(fieldValue, fieldType)) {
_errorReporter.reportErrorForNode(
CompileTimeErrorCode.CONST_CONSTRUCTOR_FIELD_TYPE_MISMATCH,

View file

@ -122,9 +122,15 @@ class ClassAugmentationElementImpl extends InterfaceAugmentationElementImpl
}
set augmentationTarget(ClassOrAugmentationElementMixin? value) {
value?._augmentation = this;
_augmentationTarget = value;
}
@override
ClassElementImpl? get augmentedDeclaration {
return augmentationTarget?.augmentedDeclaration;
}
@override
ElementKind get kind => ElementKind.CLASS_AUGMENTATION;
@ -136,6 +142,7 @@ class ClassAugmentationElementImpl extends InterfaceAugmentationElementImpl
/// An [InterfaceElementImpl] which is a class.
class ClassElementImpl extends ClassOrMixinElementImpl<ClassElementLinkedData>
with ClassOrAugmentationElementMixin<ClassElementLinkedData>
implements ClassElement {
/// Initialize a newly created class element to have the given [name] at the
/// given [offset] in the file that contains the declaration of this element.
@ -198,16 +205,13 @@ class ClassElementImpl extends ClassOrMixinElementImpl<ClassElementLinkedData>
}
@override
ClassAugmentationElement? get augmentation {
AugmentedClassElement get augmented {
// TODO(scheglov) implement
throw UnimplementedError();
}
@override
AugmentedClassElement get augmented {
// TODO(scheglov) implement
throw UnimplementedError();
}
ClassElementImpl get augmentedDeclaration => this;
@override
List<ConstructorElementImpl> get constructors {
@ -656,10 +660,13 @@ mixin ClassOrAugmentationElementMixin<LinkedData extends ElementLinkedData>
ClassAugmentationElementImpl? _augmentation;
@override
ClassAugmentationElement? get augmentation {
ClassAugmentationElementImpl? get augmentation {
linkedData?.read(this);
return _augmentation;
}
@override
ClassElementImpl? get augmentedDeclaration;
}
abstract class ClassOrMixinElementImpl<LinkedData extends ElementLinkedData>
@ -703,8 +710,8 @@ class CompilationUnitElementImpl extends UriReferencedElementImpl
/// contained in this compilation unit.
List<PropertyAccessorElementImpl> _accessors = const [];
/// A list containing all of the classes contained in this compilation unit.
List<ClassElementImpl> _classes = const [];
List<ClassAugmentationElementImpl> _classAugmentations = const [];
/// A list containing all of the enums contained in this compilation unit.
List<EnumElementImpl> _enums = const [];
@ -764,6 +771,18 @@ class CompilationUnitElementImpl extends UriReferencedElementImpl
...topLevelVariables,
];
@override
List<ClassAugmentationElementImpl> get classAugmentations {
return _classAugmentations;
}
set classAugmentations(List<ClassAugmentationElementImpl> elements) {
for (final element in elements) {
element.enclosingElement = this;
}
_classAugmentations = elements;
}
@override
List<ClassElementImpl> get classes {
return _classes;
@ -1037,8 +1056,8 @@ class ConstructorElementImpl extends ExecutableElementImpl
super.enclosingElement2 as InterfaceElementImpl;
@override
NamedInstanceElement get enclosingElement2 =>
super.enclosingElement2 as NamedInstanceElement;
NamedInstanceOrAugmentationElement get enclosingElement2 =>
super.enclosingElement2 as NamedInstanceOrAugmentationElement;
@override
bool get isConst {
@ -1100,13 +1119,20 @@ class ConstructorElementImpl extends ExecutableElementImpl
}
@override
NamedInstanceType get returnType2 =>
ElementTypeProvider.current.getExecutableReturnType(this)
as NamedInstanceType;
DartType get returnType2 =>
ElementTypeProvider.current.getExecutableReturnType(this);
@override
DartType get returnTypeInternal {
return _returnType ??= enclosingElement2.thisType;
var result = _returnType;
if (result != null) {
return result;
}
final augmentedDeclaration = enclosingElement2.augmentedDeclaration;
result = augmentedDeclaration?.thisType;
result ??= InvalidTypeImpl.instance;
return _returnType = result;
}
ConstructorElement? get superConstructor {
@ -2597,6 +2623,9 @@ class EnumElementImpl extends InterfaceElementImpl<EnumElementLinkedData>
throw UnimplementedError();
}
@override
EnumElementImpl get augmentedDeclaration => this;
List<FieldElementImpl> get constants {
return fields.where((field) => field.isEnumConstant).toList();
}
@ -2881,6 +2910,9 @@ class ExtensionElementImpl extends _ExistingElementImpl
throw UnimplementedError();
}
@override
ExtensionElementImpl get augmentedDeclaration => this;
@override
List<Element> get children => [
...super.children,
@ -3371,6 +3403,9 @@ class InlineClassElementImpl extends NamedInstanceElementImpl
throw UnimplementedError();
}
@override
InlineClassElementImpl get augmentedDeclaration => this;
@override
List<InlineClassType> get implemented {
// TODO(scheglov) implement
@ -3408,8 +3443,12 @@ mixin InlineClassOrAugmentationElementMixin
on NamedInstanceOrAugmentationElementMixin
implements InlineClassOrAugmentationElement {}
abstract class InstanceAugmentationElementImpl extends _ExistingElementImpl
with TypeParameterizedElementMixin, InstanceOrAugmentationElementMixin {
abstract class InstanceAugmentationElementImpl<
LinkedData extends ElementLinkedData> extends _ExistingElementImpl
with
TypeParameterizedElementMixin,
InstanceOrAugmentationElementMixin<LinkedData>
implements InstanceAugmentationElement {
InstanceAugmentationElementImpl(super.name, super.offset);
}
@ -3418,7 +3457,7 @@ abstract class InstanceElementImpl<LinkedData extends ElementLinkedData>
with
TypeParameterizedElementMixin,
InstanceOrAugmentationElementMixin<LinkedData>
implements InstanceOrAugmentationElement {
implements InstanceElement {
InstanceElementImpl(super.name, super.nameOffset);
}
@ -4970,6 +5009,9 @@ class MixinElementImpl extends ClassOrMixinElementImpl<MixinElementLinkedData>
throw UnimplementedError();
}
@override
MixinElementImpl get augmentedDeclaration => this;
@override
List<InterfaceType> get mixins => const [];
@ -5437,7 +5479,7 @@ abstract class NamedInstanceAugmentationElementImpl
abstract class NamedInstanceElementImpl<LinkedData extends ElementLinkedData>
extends InstanceElementImpl<LinkedData>
with NamedInstanceOrAugmentationElementMixin<LinkedData>
implements NamedInstanceOrAugmentationElement {
implements NamedInstanceElement {
NamedInstanceElementImpl(super.name, super.nameOffset);
}

View file

@ -26,7 +26,7 @@ extension ElementAnnotationExtensions on ElementAnnotation {
}
}
} else if (element is ConstructorElement) {
instanceElement = element.enclosingElement2;
instanceElement = element.enclosingElement2.augmentedDeclaration;
}
if (instanceElement == null) {
return const <TargetKind>{};

View file

@ -49,7 +49,9 @@ class ConstructorMember extends ExecutableMember
InterfaceElement get enclosingElement => declaration.enclosingElement;
@override
NamedInstanceElement get enclosingElement2 => declaration.enclosingElement2;
NamedInstanceOrAugmentationElement get enclosingElement2 {
return declaration.enclosingElement2;
}
@override
bool get isConst => declaration.isConst;

View file

@ -31,6 +31,8 @@ class NullSafeApiVerifier {
if (constructor == null) return;
final type = constructor.returnType2;
if (type is! InterfaceType) return;
final isFutureValue = type.isDartAsyncFuture && constructor.name == 'value';
if (isFutureValue) {

View file

@ -116,8 +116,13 @@ class TypeArgumentsVerifier {
return;
}
var returnType = constructorElement.returnType2;
if (returnType is! InterfaceType) {
return;
}
// Check that type arguments are regular-bounded.
var typeArguments = constructorElement.returnType2.typeArguments;
var typeArguments = returnType.typeArguments;
var substitution = Substitution.fromPairs(typeParameters, typeArguments);
for (var i = 0; i < typeArguments.length; i++) {
var typeParameter = typeParameters[i];

View file

@ -102,7 +102,7 @@ class ClassAugmentationElementLinkedData
);
_readTypeParameters(reader, element.typeParameters);
element.augmentationTarget =
reader.readElement() as ClassOrAugmentationElementMixin?;
reader.readElement() as ClassOrAugmentationElementMixin;
element.mixins = reader._readInterfaceTypeList();
element.interfaces = reader._readInterfaceTypeList();
applyConstantOffsets?.perform();
@ -620,6 +620,50 @@ class LibraryReader {
);
}
ClassAugmentationElementImpl _readClassAugmentationElement(
CompilationUnitElementImpl unitElement,
Reference unitReference,
) {
var resolutionOffset = _baseResolutionOffset + _reader.readUInt30();
var name = _reader.readStringReference();
var reference = unitReference.getChild('@classAugmentation').getChild(name);
var element = ClassAugmentationElementImpl(name, -1);
var linkedData = ClassAugmentationElementLinkedData(
reference: reference,
libraryReader: this,
unitElement: unitElement,
offset: resolutionOffset,
);
element.setLinkedData(reference, linkedData);
ClassAugmentationElementFlags.read(_reader, element);
element.typeParameters = _readTypeParameters();
var fields = <FieldElementImpl>[];
var accessors = <PropertyAccessorElementImpl>[];
_readFields(unitElement, element, reference, accessors, fields);
_readPropertyAccessors(
unitElement, element, reference, accessors, fields, '@field');
element.fields = fields.toFixedList();
element.accessors = accessors.toFixedList();
element.constructors = _readConstructors(unitElement, element, reference);
element.methods = _readMethods(unitElement, element, reference);
return element;
}
void _readClassAugmentations(
CompilationUnitElementImpl unitElement,
Reference unitReference,
) {
unitElement.classAugmentations = _reader.readTypedList(() {
return _readClassAugmentationElement(unitElement, unitReference);
});
}
ClassElementImpl _readClassElement(
CompilationUnitElementImpl unitElement,
Reference unitReference,
@ -693,7 +737,7 @@ class LibraryReader {
List<ConstructorElementImpl> _readConstructors(
CompilationUnitElementImpl unitElement,
InterfaceElementImpl classElement,
NamedInstanceOrAugmentationElementMixin classElement,
Reference classReference,
) {
var containerRef = classReference.getChild('@constructor');
@ -1522,6 +1566,7 @@ class LibraryReader {
unitElement.isSynthetic = _reader.readBool();
_readClasses(unitElement, unitReference);
_readClassAugmentations(unitElement, unitReference);
_readEnums(unitElement, unitReference);
_readExtensions(unitElement, unitReference);
_readFunctions(unitElement, unitReference);

View file

@ -137,6 +137,32 @@ class BundleWriter {
_writeDirectiveUri(element.uri);
}
void _writeClassAugmentationElement(ClassAugmentationElementImpl element) {
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.name);
ClassAugmentationElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata);
_writeTypeParameters(element.typeParameters, () {
_resolutionSink.writeElement(element.augmentationTarget);
_resolutionSink._writeTypeList(element.mixins);
_resolutionSink._writeTypeList(element.interfaces);
_writeList(
element.fields.where((e) => !e.isSynthetic).toList(),
_writeFieldElement,
);
_writeList(
element.accessors.where((e) => !e.isSynthetic).toList(),
_writePropertyAccessorElement,
);
_writeList(element.constructors, _writeConstructorElement);
_writeList(element.methods, _writeMethodElement);
});
}
void _writeClassElement(ClassElementImpl element) {
_sink.writeUInt30(_resolutionSink.offset);
@ -533,6 +559,7 @@ class BundleWriter {
_sink._writeOptionalStringReference(unitElement.uri);
_sink.writeBool(unitElement.isSynthetic);
_writeList(unitElement.classes, _writeClassElement);
_writeList(unitElement.classAugmentations, _writeClassAugmentationElement);
_writeList(unitElement.enums, _writeEnumElement);
_writeList(unitElement.extensions, _writeExtensionElement);
_writeList(unitElement.functions, _writeFunctionElement);

View file

@ -48,6 +48,7 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
_visitPropertyFirst<TopLevelVariableDeclaration>(unit.declarations);
_unitElement.accessors = _enclosingContext.propertyAccessors;
_unitElement.classes = _enclosingContext.classes;
_unitElement.classAugmentations = _enclosingContext.classAugmentations;
_unitElement.enums = _enclosingContext.enums;
_unitElement.extensions = _enclosingContext.extensions;
_unitElement.functions = _enclosingContext.functions;
@ -83,9 +84,48 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
}
@override
void visitClassAugmentationDeclaration(ClassAugmentationDeclaration node) {
// TODO: implement visitClassAugmentationDeclaration
// super.visitClassAugmentationDeclaration(node);
void visitClassAugmentationDeclaration(
covariant ClassAugmentationDeclarationImpl node,
) {
final nameToken = node.name;
final name = nameToken.lexeme;
final element = ClassAugmentationElementImpl(name, nameToken.offset);
element.metadata = _buildAnnotations(node.metadata);
_setCodeRange(element, node);
_setDocumentation(element, node);
node.declaredElement = element;
_linker.elementNodes[element] = node;
final reference = _enclosingContext.addClassAugmentation(name, element);
_libraryBuilder.declare(name, reference);
final holder = _EnclosingContext(reference, element);
_withEnclosing(holder, () {
final typeParameters = node.typeParameters;
if (typeParameters != null) {
typeParameters.accept(this);
element.typeParameters = holder.typeParameters;
}
});
node.withClause?.accept(this);
node.implementsClause?.accept(this);
_withEnclosing(holder, () {
_visitPropertyFirst<FieldDeclaration>(node.members);
});
element.accessors = holder.propertyAccessors;
element.constructors = holder.constructors;
element.fields = holder.fields;
element.methods = holder.methods;
// TODO(scheglov) We cannot do this anymore.
// Not for class augmentations, not for classes.
// At the time when we build, we don't know all fields yet.
// _resolveConstructorFieldFormals(element);
}
@override
@ -1341,6 +1381,7 @@ class _EnclosingContext {
final Reference reference;
final ElementImpl element;
final List<ClassElementImpl> _classes = [];
final List<ClassAugmentationElementImpl> _classAugmentations = [];
final List<ConstructorElementImpl> _constructors = [];
final List<EnumElementImpl> _enums = [];
final List<ExtensionElementImpl> _extensions = [];
@ -1368,6 +1409,10 @@ class _EnclosingContext {
this.hasDefaultFormalParameters = false,
});
List<ClassAugmentationElementImpl> get classAugmentations {
return _classAugmentations.toFixedList();
}
List<ClassElementImpl> get classes {
return _classes.toFixedList();
}
@ -1432,6 +1477,14 @@ class _EnclosingContext {
return _bindReference('@class', name, element);
}
Reference addClassAugmentation(
String name,
ClassAugmentationElementImpl element,
) {
_classAugmentations.add(element);
return _bindReference('@classAugmentation', name, element);
}
Reference addConstructor(ConstructorElementImpl element) {
_constructors.add(element);

View file

@ -6,6 +6,20 @@ import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/summary2/data_reader.dart';
import 'package:analyzer/src/summary2/data_writer.dart';
class ClassAugmentationElementFlags {
static void read(
SummaryDataReader reader,
ClassAugmentationElementImpl element,
) {
reader.readUInt30();
}
static void write(BufferedSink sink, ClassAugmentationElementImpl element) {
var result = 0;
sink.writeUInt30(result);
}
}
class ClassElementFlags {
static const int _isAbstract = 1 << 0;
static const int _isBase = 1 << 1;

View file

@ -101,6 +101,12 @@ class InformativeDataApplier {
_applyToClassDeclaration,
);
forCorrespondingPairs(
unitElement.classAugmentations,
unitInfo.classAugmentationDeclarations,
_applyToClassAugmentationDeclaration,
);
forCorrespondingPairs(
unitElement.classes
.where((element) => element.isMixinApplication)
@ -205,6 +211,33 @@ class InformativeDataApplier {
);
}
void _applyToClassAugmentationDeclaration(
ClassAugmentationElementImpl element,
_InfoClassDeclaration info,
) {
element.setCodeRange(info.codeOffset, info.codeLength);
element.nameOffset = info.nameOffset;
element.documentationComment = info.documentationComment;
_applyToTypeParameters(
element.typeParameters_unresolved,
info.typeParameters,
);
_applyToConstructors(element.constructors, info.constructors);
_applyToFields(element.fields, info.fields);
_applyToAccessors(element.accessors, info.accessors);
_applyToMethods(element.methods, info.methods);
var linkedData = element.linkedData as ClassAugmentationElementLinkedData;
linkedData.applyConstantOffsets = ApplyConstantOffsets(
info.constantOffsets,
(applier) {
applier.applyToMetadata(element);
applier.applyToTypeParameters(element.typeParameters);
},
);
}
void _applyToClassDeclaration(
ClassElement element,
_InfoClassDeclaration info,
@ -1130,6 +1163,22 @@ class _InformativeDataWriter {
);
});
sink.writeList2<ClassAugmentationDeclaration>(unit.declarations, (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
sink.writeUInt30(node.name.offset);
_writeDocumentationComment(node);
_writeTypeParameters(node.typeParameters);
_writeConstructors(node.members);
_writeFields(node.members);
_writeGettersSetters(node.members);
_writeMethods(node.members);
_writeOffsets(
metadata: node.metadata,
typeParameters: node.typeParameters,
);
});
sink.writeList2<ClassTypeAlias>(unit.declarations, (node) {
sink.writeUInt30(node.offset);
sink.writeUInt30(node.length);
@ -1620,6 +1669,7 @@ class _InfoUnit {
final List<_InfoExport> exports;
final List<_InfoPart> parts;
final List<_InfoClassDeclaration> classDeclarations;
final List<_InfoClassDeclaration> classAugmentationDeclarations;
final List<_InfoClassTypeAlias> classTypeAliases;
final List<_InfoClassDeclaration> enums;
final List<_InfoClassDeclaration> extensions;
@ -1650,6 +1700,9 @@ class _InfoUnit {
classDeclarations: reader.readTypedList(
() => _InfoClassDeclaration(reader),
),
classAugmentationDeclarations: reader.readTypedList(
() => _InfoClassDeclaration(reader),
),
classTypeAliases: reader.readTypedList(
() => _InfoClassTypeAlias(reader),
),
@ -1691,6 +1744,7 @@ class _InfoUnit {
required this.exports,
required this.parts,
required this.classDeclarations,
required this.classAugmentationDeclarations,
required this.classTypeAliases,
required this.enums,
required this.extensions,

View file

@ -175,6 +175,7 @@ class LibraryBuilder {
}
elementBuilder.buildDeclarationElements(linkingUnit.node);
}
_mergeAugmentations();
_declareDartCoreDynamicNever();
}
@ -759,6 +760,21 @@ class LibraryBuilder {
}
}
void _mergeAugmentations() {
final targets = <String, ClassOrAugmentationElementMixin>{};
for (final unitElement in element.units) {
for (final classElement in unitElement.classes) {
targets[classElement.name] = classElement;
}
for (final augmentation in unitElement.classAugmentations) {
final name = augmentation.name;
// TODO(scheglov) create synthetic instead of null assert
augmentation.augmentationTarget = targets[name]!;
targets[augmentation.name] = augmentation;
}
}
}
static void build(Linker linker, LibraryFileKind inputLibrary) {
final elementFactory = linker.elementFactory;
final rootReference = linker.rootReference;

View file

@ -39,6 +39,12 @@ class MetadataResolver extends ThrowingAstVisitor<void> {
node.metadata.accept(this);
}
@override
void visitClassAugmentationDeclaration(ClassAugmentationDeclaration node) {
// TODO: implement visitClassAugmentationDeclaration
// super.visitClassAugmentationDeclaration(node);
}
@override
void visitClassDeclaration(ClassDeclaration node) {
node.metadata.accept(this);

View file

@ -150,6 +150,15 @@ class _ElementWriter {
);
}
void _writeAugmentation(InterfaceOrAugmentationElementMixin e) {
if (e case ClassOrAugmentationElementMixin e) {
final augmentation = e.augmentation;
if (augmentation != null) {
_elementPrinter.writeNamedElement('augmentation', augmentation);
}
}
}
void _writeAugmentationElement(LibraryAugmentationElementImpl e) {
_writeLibraryOrAugmentationElement(e);
}
@ -168,6 +177,27 @@ class _ElementWriter {
});
}
void _writeAugmentationTarget(InterfaceOrAugmentationElementMixin e) {
if (e case InstanceAugmentationElementImpl e) {
_elementPrinter.writeNamedElement(
'augmentationTarget',
e.augmentationTarget,
);
}
}
void _writeAugmentedDeclaration(InterfaceOrAugmentationElementMixin e) {
final augmentedDeclaration = e.augmentedDeclaration;
if (identical(augmentedDeclaration, e)) {
return;
}
_elementPrinter.writeNamedElement(
'augmentedDeclaration',
augmentedDeclaration,
);
}
void _writeBodyModifiers(ExecutableElement e) {
if (e.isAsynchronous) {
expect(e.isSynchronous, isFalse);
@ -186,79 +216,6 @@ class _ElementWriter {
}
}
void _writeClassElement(InterfaceElement e) {
_sink.writeIndentedLine(() {
if (e is ClassElement) {
_sink.writeIf(e.isAbstract, 'abstract ');
_sink.writeIf(e.isMacro, 'macro ');
_sink.writeIf(e.isSealed, 'sealed ');
_sink.writeIf(e.isBase, 'base ');
_sink.writeIf(e.isInterface, 'interface ');
_sink.writeIf(e.isFinal, 'final ');
_sink.writeIf(e.isInline, 'inline ');
_sink.writeIf(e.isMixinClass, 'mixin ');
}
_sink.writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
if (e is EnumElement) {
_sink.write('enum ');
} else if (e is MixinElement) {
_sink.writeIf(e.isBase, 'base ');
_sink.write('mixin ');
} else {
_sink.write('class ');
}
if (e is ClassElement) {
_sink.writeIf(e.isMixinApplication, 'alias ');
}
_writeName(e);
});
_sink.withIndent(() {
_writeDocumentation(e);
_writeMetadata(e);
_writeSinceSdkVersion(e);
_writeCodeRange(e);
_writeTypeParameterElements(e.typeParameters);
final supertype = e.supertype;
if (supertype != null &&
(supertype.element.name != 'Object' || e.mixins.isNotEmpty)) {
_writeType('supertype', supertype);
}
if (e is MixinElement) {
var superclassConstraints = e.superclassConstraints;
if (superclassConstraints.isEmpty) {
throw StateError('At least Object is expected.');
}
_elementPrinter.writeTypeList(
'superclassConstraints',
superclassConstraints,
);
}
_elementPrinter.writeTypeList('mixins', e.mixins);
_elementPrinter.writeTypeList('interfaces', e.interfaces);
_writeElements('fields', e.fields, _writePropertyInducingElement);
var constructors = e.constructors;
if (e is MixinElement) {
expect(constructors, isEmpty);
} else if (configuration.withConstructors) {
expect(constructors, isNotEmpty);
_writeElements('constructors', constructors, _writeConstructorElement);
}
_writeElements('accessors', e.accessors, _writePropertyAccessorElement);
_writeElements('methods', e.methods, _writeMethodElement);
});
_assertNonSyntheticElementSelf(e);
}
void _writeCodeRange(Element e) {
if (configuration.withCodeRanges && !e.isSynthetic) {
e as ElementImpl;
@ -532,6 +489,92 @@ class _ElementWriter {
}
}
void _writeInterfaceOrAugmentationElement(
InterfaceOrAugmentationElementMixin e,
) {
_sink.writeIndentedLine(() {
if (e is InstanceAugmentationElementImpl) {
_sink.write('augment ');
}
if (e is ClassElementImpl) {
_sink.writeIf(e.isAbstract, 'abstract ');
_sink.writeIf(e.isMacro, 'macro ');
_sink.writeIf(e.isSealed, 'sealed ');
_sink.writeIf(e.isBase, 'base ');
_sink.writeIf(e.isInterface, 'interface ');
_sink.writeIf(e.isFinal, 'final ');
_sink.writeIf(e.isInline, 'inline ');
_sink.writeIf(e.isMixinClass, 'mixin ');
}
_sink.writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
if (e is EnumElementImpl) {
_sink.write('enum ');
} else if (e is MixinElementImpl) {
_sink.writeIf(e.isBase, 'base ');
_sink.write('mixin ');
} else {
_sink.write('class ');
}
if (e is ClassElementImpl) {
_sink.writeIf(e.isMixinApplication, 'alias ');
}
_writeName(e);
});
_sink.withIndent(() {
_writeDocumentation(e);
_writeMetadata(e);
_writeSinceSdkVersion(e);
_writeCodeRange(e);
_writeTypeParameterElements(e.typeParameters);
_writeAugmentationTarget(e);
_writeAugmentedDeclaration(e);
_writeAugmentation(e);
if (e is InterfaceElementImpl) {
final supertype = e.supertype;
if (supertype != null &&
(supertype.element.name != 'Object' || e.mixins.isNotEmpty)) {
_writeType('supertype', supertype);
}
}
if (e is MixinElementImpl) {
var superclassConstraints = e.superclassConstraints;
if (superclassConstraints.isEmpty) {
throw StateError('At least Object is expected.');
}
_elementPrinter.writeTypeList(
'superclassConstraints',
superclassConstraints,
);
}
_elementPrinter.writeTypeList('mixins', e.mixins);
_elementPrinter.writeTypeList('interfaces', e.interfaces);
_writeElements('fields', e.fields, _writePropertyInducingElement);
var constructors = e.constructors;
if (e is MixinOrAugmentationElement) {
expect(constructors, isEmpty);
} else if (configuration.withConstructors) {
if (e is NamedInstanceElement) {
expect(constructors, isNotEmpty);
}
_writeElements('constructors', constructors, _writeConstructorElement);
}
_writeElements('accessors', e.accessors, _writePropertyAccessorElement);
_writeElements('methods', e.methods, _writeMethodElement);
});
_assertNonSyntheticElementSelf(e);
}
void _writeLibraryAugmentations(LibraryElementImpl e) {
if (configuration.withLibraryAugmentations) {
final augmentations = e.augmentations;
@ -723,7 +766,7 @@ class _ElementWriter {
_sink.withIndent(() {
_writeMetadata(e);
if (uri is DirectiveUriWithUnit) {
if (uri is DirectiveUriWithUnitImpl) {
_writeUnitElement(uri.unit);
}
});
@ -999,11 +1042,16 @@ class _ElementWriter {
_writeElements('typeParameters', elements, _writeTypeParameterElement);
}
void _writeUnitElement(CompilationUnitElement e) {
_writeElements('classes', e.classes, _writeClassElement);
_writeElements('enums', e.enums, _writeClassElement);
void _writeUnitElement(CompilationUnitElementImpl e) {
_writeElements('classes', e.classes, _writeInterfaceOrAugmentationElement);
_writeElements(
'classAugmentations',
e.classAugmentations,
_writeInterfaceOrAugmentationElement,
);
_writeElements('enums', e.enums, _writeInterfaceOrAugmentationElement);
_writeElements('extensions', e.extensions, _writeExtensionElement);
_writeElements('mixins', e.mixins, _writeClassElement);
_writeElements('mixins', e.mixins, _writeInterfaceOrAugmentationElement);
_writeElements('typeAliases', e.typeAliases, _writeTypeAliasElement);
_writeElements(
'topLevelVariables',
@ -1038,10 +1086,3 @@ class _IdMap {
}
}
}
extension on ClassElement {
bool get isMacro {
final self = this;
return self is ClassElementImpl && self.isMacro;
}
}

View file

@ -24,14 +24,61 @@ main() {
});
}
mixin ClassAugmentationElementsMixin on ElementsBaseTest {
test_augmentationTarget() async {
newFile('$testPackageLibPath/a.dart', r'''
library augment 'test.dart';
import augment 'b.dart';
augment class A {}
''');
newFile('$testPackageLibPath/b.dart', r'''
library augment 'a.dart';
augment class A {}
''');
var library = await buildLibrary(r'''
import augment 'a.dart';
class A {}
''');
checkElementText(library, r'''
library
augmentationImports
package:test/a.dart
augmentationImports
package:test/b.dart
definingUnit
classAugmentations
augment class A @40
augmentationTarget: self::@augmentation::package:test/a.dart::@classAugmentation::A
augmentedDeclaration: self::@class::A
definingUnit
classAugmentations
augment class A @68
augmentationTarget: self::@class::A
augmentedDeclaration: self::@class::A
augmentation: self::@augmentation::package:test/b.dart::@classAugmentation::A
definingUnit
classes
class A @31
augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A
constructors
synthetic @-1
''');
}
}
@reflectiveTest
class ElementsFromBytesTest extends ElementsTest {
class ElementsFromBytesTest extends ElementsTest
with ClassAugmentationElementsMixin {
@override
bool get keepLinkingLibraries => false;
}
@reflectiveTest
class ElementsKeepLinkingTest extends ElementsTest {
class ElementsKeepLinkingTest extends ElementsTest
with ClassAugmentationElementsMixin {
@override
bool get keepLinkingLibraries => true;
}