Version 3.9.0-65.0.dev Merge 7a83c82b4f483b72a2467a6440f187384508ebd8 into dev
diff --git a/pkg/front_end/lib/src/builder/library_builder.dart b/pkg/front_end/lib/src/builder/library_builder.dart index b30555f..a8bbbe6 100644 --- a/pkg/front_end/lib/src/builder/library_builder.dart +++ b/pkg/front_end/lib/src/builder/library_builder.dart
@@ -228,8 +228,9 @@ {required bool allowPartInParts}); void buildOutlineExpressions( - Annotatable annotatable, BodyBuilderContext bodyBuilderContext, - {required bool createFileUriExpression}); + {required Annotatable annotatable, + required Uri annotatableFileUri, + required BodyBuilderContext bodyBuilderContext}); /// Reports that [feature] is not enabled, using [charOffset] and /// [length] for the location of the message.
diff --git a/pkg/front_end/lib/src/builder/metadata_builder.dart b/pkg/front_end/lib/src/builder/metadata_builder.dart index a061429..e2e79e2 100644 --- a/pkg/front_end/lib/src/builder/metadata_builder.dart +++ b/pkg/front_end/lib/src/builder/metadata_builder.dart
@@ -32,7 +32,9 @@ /// Expression for an already parsed annotation. Expression? _expression; - MetadataBuilder(Token this._atToken) + final Uri fileUri; + + MetadataBuilder(Token this._atToken, this.fileUri) : atOffset = _atToken.charOffset, hasPatch = _atToken.next?.lexeme == 'patch'; @@ -51,13 +53,12 @@ _unresolvedSharedExpressionForTesting; static void buildAnnotations( - Annotatable parent, - List<MetadataBuilder>? metadata, - BodyBuilderContext bodyBuilderContext, - SourceLibraryBuilder library, - Uri fileUri, - LookupScope scope, - {bool createFileUriExpression = false}) { + {required Annotatable annotatable, + required Uri annotatableFileUri, + required List<MetadataBuilder>? metadata, + required BodyBuilderContext bodyBuilderContext, + required SourceLibraryBuilder libraryBuilder, + required LookupScope scope}) { if (metadata == null) return; // [BodyBuilder] used to build annotations from [Token]s. @@ -74,33 +75,42 @@ for (int i = 0; i < metadata.length; ++i) { MetadataBuilder annotationBuilder = metadata[i]; + bool createFileUriExpression = + annotatableFileUri != annotationBuilder.fileUri; Token? beginToken = annotationBuilder._atToken; if (beginToken != null) { if (computeSharedExpressionForTesting) { // Coverage-ignore-block(suite): Not run. annotationBuilder._sharedExpression = _parseSharedExpression( - library.loader, beginToken, library.importUri, fileUri, scope); + libraryBuilder.loader, + beginToken, + libraryBuilder.importUri, + annotationBuilder.fileUri, + scope); if (delaySharedExpressionLookupForTesting) { annotationBuilder._unresolvedSharedExpressionForTesting = - _parseSharedExpression(library.loader, beginToken, - library.importUri, fileUri, scope, + _parseSharedExpression(libraryBuilder.loader, beginToken, + libraryBuilder.importUri, annotationBuilder.fileUri, scope, delayLookupForTesting: true); } } - bodyBuilder ??= library.loader.createBodyBuilderForOutlineExpression( - library, bodyBuilderContext, scope, fileUri); + bodyBuilder ??= libraryBuilder.loader + .createBodyBuilderForOutlineExpression(libraryBuilder, + bodyBuilderContext, scope, annotationBuilder.fileUri); Expression annotation = bodyBuilder.parseAnnotation(beginToken); annotationBuilder._atToken = null; if (createFileUriExpression) { - annotation = new FileUriExpression(annotation, fileUri) - ..fileOffset = annotationBuilder.atOffset; + annotation = + new FileUriExpression(annotation, annotationBuilder.fileUri) + ..fileOffset = annotationBuilder.atOffset; } // Record the index of [annotation] in `parent.annotations`. - parsedAnnotationBuilders[annotationBuilder] = parent.annotations.length; + parsedAnnotationBuilders[annotationBuilder] = + annotatable.annotations.length; // It is important for the inference and backlog computations that the // annotation is already a child of [parent]. - parent.addAnnotation(annotation); + annotatable.addAnnotation(annotation); } else { // The annotation is needed for multiple declarations so we need to // clone the expression to use it more than once. For instance @@ -124,22 +134,23 @@ cloner.cloneInContext(annotationBuilder._expression!); // Coverage-ignore(suite): Not run. if (createFileUriExpression && annotation is! FileUriExpression) { - annotation = new FileUriExpression(annotation, fileUri) - ..fileOffset = annotationBuilder.atOffset; + annotation = + new FileUriExpression(annotation, annotationBuilder.fileUri) + ..fileOffset = annotationBuilder.atOffset; } - parent.addAnnotation(annotation); + annotatable.addAnnotation(annotation); } } if (bodyBuilder != null) { // TODO(johnniwinther): Avoid potentially inferring annotations multiple // times. - bodyBuilder.inferAnnotations(parent, parent.annotations); + bodyBuilder.inferAnnotations(annotatable, annotatable.annotations); bodyBuilder.performBacklogComputations(); for (MapEntry<MetadataBuilder, int> entry in parsedAnnotationBuilders.entries) { MetadataBuilder annotationBuilder = entry.key; int index = entry.value; - annotationBuilder._expression = parent.annotations[index]; + annotationBuilder._expression = annotatable.annotations[index]; } } }
diff --git a/pkg/front_end/lib/src/fragment/class/declaration.dart b/pkg/front_end/lib/src/fragment/class/declaration.dart index 3f105ba..52fba67 100644 --- a/pkg/front_end/lib/src/fragment/class/declaration.dart +++ b/pkg/front_end/lib/src/fragment/class/declaration.dart
@@ -20,6 +20,7 @@ void buildOutlineExpressions( {required Annotatable annotatable, + required Uri annotatableFileUri, required SourceLibraryBuilder libraryBuilder, required ClassHierarchy classHierarchy, required BodyBuilderContext bodyBuilderContext, @@ -69,18 +70,18 @@ @override void buildOutlineExpressions( {required Annotatable annotatable, + required Uri annotatableFileUri, required SourceLibraryBuilder libraryBuilder, required ClassHierarchy classHierarchy, required BodyBuilderContext bodyBuilderContext, required bool createFileUriExpression}) { MetadataBuilder.buildAnnotations( - annotatable, - _fragment.metadata, - bodyBuilderContext, - libraryBuilder, - _fragment.fileUri, - _fragment.enclosingScope, - createFileUriExpression: createFileUriExpression); + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + metadata: _fragment.metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope); } @override @@ -133,18 +134,18 @@ @override void buildOutlineExpressions( {required Annotatable annotatable, + required Uri annotatableFileUri, required SourceLibraryBuilder libraryBuilder, required ClassHierarchy classHierarchy, required BodyBuilderContext bodyBuilderContext, required bool createFileUriExpression}) { MetadataBuilder.buildAnnotations( - annotatable, - _fragment.metadata, - bodyBuilderContext, - libraryBuilder, - _fragment.fileUri, - _fragment.enclosingScope, - createFileUriExpression: createFileUriExpression); + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + metadata: _fragment.metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope); } @override @@ -198,18 +199,18 @@ @override void buildOutlineExpressions( {required Annotatable annotatable, + required Uri annotatableFileUri, required SourceLibraryBuilder libraryBuilder, required ClassHierarchy classHierarchy, required BodyBuilderContext bodyBuilderContext, required bool createFileUriExpression}) { MetadataBuilder.buildAnnotations( - annotatable, - _fragment.metadata, - bodyBuilderContext, - libraryBuilder, - _fragment.fileUri, - _fragment.enclosingScope, - createFileUriExpression: createFileUriExpression); + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + metadata: _fragment.metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope); } @override @@ -266,6 +267,7 @@ @override void buildOutlineExpressions( {required Annotatable annotatable, + required Uri annotatableFileUri, required SourceLibraryBuilder libraryBuilder, required ClassHierarchy classHierarchy, required BodyBuilderContext bodyBuilderContext, @@ -319,18 +321,18 @@ @override void buildOutlineExpressions( {required Annotatable annotatable, + required Uri annotatableFileUri, required SourceLibraryBuilder libraryBuilder, required ClassHierarchy classHierarchy, required BodyBuilderContext bodyBuilderContext, required bool createFileUriExpression}) { MetadataBuilder.buildAnnotations( - annotatable, - _fragment.metadata, - bodyBuilderContext, - libraryBuilder, - _fragment.fileUri, - _fragment.enclosingScope, - createFileUriExpression: createFileUriExpression); + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + metadata: _fragment.metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope); } @override
diff --git a/pkg/front_end/lib/src/fragment/constructor/declaration.dart b/pkg/front_end/lib/src/fragment/constructor/declaration.dart index 65d77af..7f87320 100644 --- a/pkg/front_end/lib/src/fragment/constructor/declaration.dart +++ b/pkg/front_end/lib/src/fragment/constructor/declaration.dart
@@ -82,11 +82,11 @@ void buildOutlineExpressions({ required Iterable<Annotatable> annotatables, + required Uri annotatablesFileUri, required SourceLibraryBuilder libraryBuilder, required DeclarationBuilder declarationBuilder, required SourceConstructorBuilderImpl constructorBuilder, required ClassHierarchy classHierarchy, - required bool createFileUriExpression, required List<DelayedDefaultValueCloner> delayedDefaultValueCloners, }); @@ -531,12 +531,12 @@ void _buildMetadataForOutlineExpressions({ required Iterable<Annotatable> annotatables, + required Uri annotatablesFileUri, required SourceLibraryBuilder libraryBuilder, required DeclarationBuilder declarationBuilder, required SourceConstructorBuilderImpl constructorBuilder, required BodyBuilderContext bodyBuilderContext, required ClassHierarchy classHierarchy, - required bool createFileUriExpression, }); void _buildTypeParametersAndFormalsForOutlineExpressions({ @@ -549,11 +549,11 @@ @override void buildOutlineExpressions({ required Iterable<Annotatable> annotatables, + required Uri annotatablesFileUri, required SourceLibraryBuilder libraryBuilder, required DeclarationBuilder declarationBuilder, required SourceConstructorBuilderImpl constructorBuilder, required ClassHierarchy classHierarchy, - required bool createFileUriExpression, required List<DelayedDefaultValueCloner> delayedDefaultValueCloners, }) { formals?.infer(classHierarchy); @@ -561,12 +561,12 @@ createBodyBuilderContext(constructorBuilder); _buildMetadataForOutlineExpressions( annotatables: annotatables, + annotatablesFileUri: annotatablesFileUri, libraryBuilder: libraryBuilder, declarationBuilder: declarationBuilder, constructorBuilder: constructorBuilder, bodyBuilderContext: bodyBuilderContext, - classHierarchy: classHierarchy, - createFileUriExpression: createFileUriExpression); + classHierarchy: classHierarchy); _buildTypeParametersAndFormalsForOutlineExpressions( libraryBuilder: libraryBuilder, declarationBuilder: declarationBuilder, @@ -845,21 +845,20 @@ @override void _buildMetadataForOutlineExpressions( {required Iterable<Annotatable> annotatables, + required Uri annotatablesFileUri, required SourceLibraryBuilder libraryBuilder, required DeclarationBuilder declarationBuilder, required SourceConstructorBuilderImpl constructorBuilder, required BodyBuilderContext bodyBuilderContext, - required ClassHierarchy classHierarchy, - required bool createFileUriExpression}) { + required ClassHierarchy classHierarchy}) { for (Annotatable annotatable in annotatables) { MetadataBuilder.buildAnnotations( - annotatable, - _fragment.metadata, - bodyBuilderContext, - libraryBuilder, - _fragment.fileUri, - _fragment.enclosingScope, - createFileUriExpression: createFileUriExpression); + annotatable: annotatable, + annotatableFileUri: annotatablesFileUri, + metadata: _fragment.metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope); } } @@ -975,12 +974,12 @@ @override void _buildMetadataForOutlineExpressions( {required Iterable<Annotatable> annotatables, + required Uri annotatablesFileUri, required SourceLibraryBuilder libraryBuilder, required DeclarationBuilder declarationBuilder, required SourceConstructorBuilderImpl constructorBuilder, required BodyBuilderContext bodyBuilderContext, - required ClassHierarchy classHierarchy, - required bool createFileUriExpression}) { + required ClassHierarchy classHierarchy}) { // There is no metadata on a primary constructor. } @@ -1109,12 +1108,12 @@ @override void _buildMetadataForOutlineExpressions( {required Iterable<Annotatable> annotatables, + required Uri annotatablesFileUri, required SourceLibraryBuilder libraryBuilder, required DeclarationBuilder declarationBuilder, required SourceConstructorBuilderImpl constructorBuilder, required BodyBuilderContext bodyBuilderContext, - required ClassHierarchy classHierarchy, - required bool createFileUriExpression}) { + required ClassHierarchy classHierarchy}) { // There is no metadata on a default enum constructor. } @@ -1380,21 +1379,20 @@ @override void _buildMetadataForOutlineExpressions( {required Iterable<Annotatable> annotatables, + required Uri annotatablesFileUri, required SourceLibraryBuilder libraryBuilder, required DeclarationBuilder declarationBuilder, required SourceConstructorBuilderImpl constructorBuilder, required BodyBuilderContext bodyBuilderContext, - required ClassHierarchy classHierarchy, - required bool createFileUriExpression}) { + required ClassHierarchy classHierarchy}) { for (Annotatable annotatable in annotatables) { MetadataBuilder.buildAnnotations( - annotatable, - _fragment.metadata, - bodyBuilderContext, - libraryBuilder, - _fragment.fileUri, - _fragment.enclosingScope, - createFileUriExpression: createFileUriExpression); + annotatable: annotatable, + annotatableFileUri: annotatablesFileUri, + metadata: _fragment.metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope); } } @@ -1505,12 +1503,12 @@ @override void _buildMetadataForOutlineExpressions( {required Iterable<Annotatable> annotatables, + required Uri annotatablesFileUri, required SourceLibraryBuilder libraryBuilder, required DeclarationBuilder declarationBuilder, required SourceConstructorBuilderImpl constructorBuilder, required BodyBuilderContext bodyBuilderContext, - required ClassHierarchy classHierarchy, - required bool createFileUriExpression}) { + required ClassHierarchy classHierarchy}) { // There is no metadata on a primary constructor. }
diff --git a/pkg/front_end/lib/src/fragment/enum_element.dart b/pkg/front_end/lib/src/fragment/enum_element.dart index 7e397bf..ee7eb68 100644 --- a/pkg/front_end/lib/src/fragment/enum_element.dart +++ b/pkg/front_end/lib/src/fragment/enum_element.dart
@@ -328,17 +328,21 @@ @override void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - List<Annotatable> annotatables, - {required bool isClassInstanceMember, - required bool createFileUriExpression}) { + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required List<Annotatable> annotatables, + required Uri annotatablesFileUri, + required bool isClassInstanceMember}) { BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); for (Annotatable annotatable in annotatables) { - buildMetadataForOutlineExpressions(libraryBuilder, - _fragment.enclosingScope, bodyBuilderContext, annotatable, metadata, - fileUri: fileUri, createFileUriExpression: createFileUriExpression); + buildMetadataForOutlineExpressions( + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope, + bodyBuilderContext: bodyBuilderContext, + annotatable: annotatable, + annotatableFileUri: annotatablesFileUri, + metadata: metadata); } } @@ -574,19 +578,19 @@ @override // Coverage-ignore(suite): Not run. - DartType get _fieldTypeInternal => _type; + DartType get fieldTypeInternal => _type; @override bool get isConst => true; @override // Coverage-ignore(suite): Not run. - void _setCovariantByClassInternal() { + void setCovariantByClassInternal() { _field!.isCovariantByClass = true; } @override - void set _fieldTypeInternal(DartType value) { + void set fieldTypeInternal(DartType value) { _type = value; _field?.type = value; }
diff --git a/pkg/front_end/lib/src/fragment/factory/declaration.dart b/pkg/front_end/lib/src/fragment/factory/declaration.dart index ddcc9b5..9075dab 100644 --- a/pkg/front_end/lib/src/fragment/factory/declaration.dart +++ b/pkg/front_end/lib/src/fragment/factory/declaration.dart
@@ -44,11 +44,12 @@ Procedure? get tearOff; void buildOutlineExpressions( - {required SourceLibraryBuilder libraryBuilder, + {required Iterable<Annotatable> annotatables, + required Uri annotatablesFileUri, + required SourceLibraryBuilder libraryBuilder, required SourceFactoryBuilder factoryBuilder, required ClassHierarchy classHierarchy, - required List<DelayedDefaultValueCloner> delayedDefaultValueCloners, - required bool createFileUriExpression}); + required List<DelayedDefaultValueCloner> delayedDefaultValueCloners}); void buildOutlineNodes( {required SourceLibraryBuilder libraryBuilder, @@ -107,6 +108,7 @@ int get fileOffset => _fragment.fullNameOffset; @override + // Coverage-ignore(suite): Not run. Uri get fileUri => _fragment.fileUri; @override @@ -146,25 +148,25 @@ @override void buildOutlineExpressions( - {required SourceLibraryBuilder libraryBuilder, + {required Iterable<Annotatable> annotatables, + required Uri annotatablesFileUri, + required SourceLibraryBuilder libraryBuilder, required SourceFactoryBuilder factoryBuilder, required ClassHierarchy classHierarchy, - required List<DelayedDefaultValueCloner> delayedDefaultValueCloners, - required bool createFileUriExpression}) { + required List<DelayedDefaultValueCloner> delayedDefaultValueCloners}) { _fragment.formals?.infer(classHierarchy); BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(factoryBuilder); - for (Annotatable annotatable in factoryBuilder.annotatables) { + for (Annotatable annotatable in annotatables) { MetadataBuilder.buildAnnotations( - annotatable, - _fragment.metadata, - bodyBuilderContext, - libraryBuilder, - _fragment.fileUri, - _fragment.enclosingScope, - createFileUriExpression: createFileUriExpression); + annotatable: annotatable, + annotatableFileUri: annotatablesFileUri, + metadata: _fragment.metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope); } if (typeParameters != null) { for (int i = 0; i < typeParameters!.length; i++) {
diff --git a/pkg/front_end/lib/src/fragment/field.dart b/pkg/front_end/lib/src/fragment/field.dart index bc8eb2b..5efeaa4 100644 --- a/pkg/front_end/lib/src/fragment/field.dart +++ b/pkg/front_end/lib/src/fragment/field.dart
@@ -4,462 +4,6 @@ part of 'fragment.dart'; -class FieldDeclarationImpl - with FieldDeclarationMixin - implements - FieldDeclaration, - FieldFragmentDeclaration, - Inferable, - InferredTypeListener { - final FieldFragment _fragment; - - late final _FieldEncoding _encoding; - - shared.Expression? _initializerExpression; - - /// Whether the body of this field has been built. - /// - /// Constant fields have their initializer built in the outline so we avoid - /// building them twice as part of the non-outline build. - bool hasBodyBeenBuilt = false; - - FieldDeclarationImpl(this._fragment) { - _fragment.declaration = this; - } - - @override - SourcePropertyBuilder get builder => _fragment.builder; - - @override - FieldQuality get fieldQuality => _fragment.modifiers.isAbstract - ? FieldQuality.Abstract - : _fragment.modifiers.isExternal - ? FieldQuality.External - : FieldQuality.Concrete; - - @override - DartType get fieldType => _encoding.type; - - @override - Uri get fileUri => _fragment.fileUri; - - @override - GetterQuality get getterQuality => _fragment.modifiers.isAbstract - ? GetterQuality.ImplicitAbstract - : _fragment.modifiers.isExternal - ? GetterQuality.ImplicitExternal - : GetterQuality.Implicit; - - @override - bool get hasInitializer => _fragment.modifiers.hasInitializer; - - @override - bool get hasSetter => _fragment.hasSetter; - - @override - // Coverage-ignore(suite): Not run. - shared.Expression? get initializerExpression => _initializerExpression; - - @override - bool get isConst => _fragment.modifiers.isConst; - - @override - bool get isEnumElement => false; - - @override - bool get isExtensionTypeDeclaredInstanceField => - builder.isExtensionTypeInstanceMember && - !_fragment.isPrimaryConstructorField; - - @override - bool get isFinal => _fragment.modifiers.isFinal; - - @override - bool get isLate => _fragment.modifiers.isLate; - - @override - bool get isStatic => - _fragment.modifiers.isStatic || builder.declarationBuilder == null; - - @override - List<ClassMember> get localMembers => _encoding.localMembers; - - @override - List<ClassMember> get localSetters => _encoding.localSetters; - - @override - List<MetadataBuilder>? get metadata => _fragment.metadata; - - @override - int get nameOffset => _fragment.nameOffset; - - @override - Member get readTarget => _encoding.readTarget; - - @override - SetterQuality get setterQuality => !hasSetter - ? SetterQuality.Absent - : _fragment.modifiers.isAbstract - ? SetterQuality.ImplicitAbstract - : _fragment.modifiers.isExternal - ? SetterQuality.ImplicitExternal - : SetterQuality.Implicit; - - @override - TypeBuilder get type => _fragment.type; - - @override - Member? get writeTarget => _encoding.writeTarget; - - @override - // Coverage-ignore(suite): Not run. - DartType get _fieldTypeInternal => _encoding.type; - - @override - void set _fieldTypeInternal(DartType value) { - _encoding.type = value; - } - - /// Builds the body of this field using [initializer] as the initializer - /// expression. - void buildBody(CoreTypes coreTypes, Expression? initializer) { - assert(!hasBodyBeenBuilt, "Body has already been built for $this."); - hasBodyBeenBuilt = true; - if (!_fragment.modifiers.hasInitializer && - initializer != null && - initializer is! NullLiteral && - // Coverage-ignore(suite): Not run. - !_fragment.modifiers.isConst && - // Coverage-ignore(suite): Not run. - !_fragment.modifiers.isFinal) { - internalProblem( - messageInternalProblemAlreadyInitialized, nameOffset, fileUri); - } - _encoding.createBodies(coreTypes, initializer); - } - - @override - Initializer buildErroneousInitializer(Expression effect, Expression value, - {required int fileOffset}) { - return _encoding.buildErroneousInitializer(effect, value, - fileOffset: fileOffset); - } - - @override - void buildFieldInitializer(InferenceHelper helper, TypeInferrer typeInferrer, - CoreTypes coreTypes, Expression? initializer) { - if (initializer != null) { - if (!hasBodyBeenBuilt) { - initializer = typeInferrer - .inferFieldInitializer(helper, fieldType, initializer) - .expression; - buildBody(coreTypes, initializer); - } - } else if (!hasBodyBeenBuilt) { - buildBody(coreTypes, null); - } - } - - @override - void buildImplicitDefaultValue() { - _encoding.buildImplicitDefaultValue(); - } - - @override - Initializer buildImplicitInitializer() { - return _encoding.buildImplicitInitializer(); - } - - @override - List<Initializer> buildInitializer(int fileOffset, Expression value, - {required bool isSynthetic}) { - return _encoding.createInitializer(fileOffset, value, - isSynthetic: isSynthetic); - } - - @override - void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - List<Annotatable> annotatables, - {required bool isClassInstanceMember, - required bool createFileUriExpression}) { - BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); - for (Annotatable annotatable in annotatables) { - buildMetadataForOutlineExpressions(libraryBuilder, - _fragment.enclosingScope, bodyBuilderContext, annotatable, metadata, - fileUri: fileUri, createFileUriExpression: createFileUriExpression); - } - // For modular compilation we need to include initializers of all const - // fields and all non-static final fields in classes with const constructors - // into the outline. - Token? token = _fragment.constInitializerToken; - if ((_fragment.modifiers.isConst || - (isFinal && - isClassInstanceMember && - (declarationBuilder as SourceClassBuilder) - .declaresConstConstructor)) && - token != null) { - LookupScope scope = _fragment.enclosingScope; - BodyBuilder bodyBuilder = libraryBuilder.loader - .createBodyBuilderForOutlineExpression( - libraryBuilder, createBodyBuilderContext(), scope, fileUri); - bodyBuilder.constantContext = _fragment.modifiers.isConst - ? ConstantContext.inferred - : ConstantContext.required; - Expression initializer = bodyBuilder.typeInferrer - .inferFieldInitializer( - bodyBuilder, fieldType, bodyBuilder.parseFieldInitializer(token)) - .expression; - buildBody(classHierarchy.coreTypes, initializer); - bodyBuilder.performBacklogComputations(); - if (computeSharedExpressionForTesting) { - // Coverage-ignore-block(suite): Not run. - _initializerExpression = parseFieldInitializer(libraryBuilder.loader, - token, libraryBuilder.importUri, fileUri, scope); - } - } - } - - @override - void buildOutlineNode(SourceLibraryBuilder libraryBuilder, - NameScheme nameScheme, BuildNodesCallback f, FieldReference references, - {required List<TypeParameter>? classTypeParameters}) { - _encoding.buildOutlineNode(libraryBuilder, nameScheme, references, - isAbstractOrExternal: - _fragment.modifiers.isAbstract || _fragment.modifiers.isExternal, - classTypeParameters: classTypeParameters); - if (type is! InferableTypeBuilder) { - fieldType = type.build(libraryBuilder, TypeUse.fieldType); - } - _encoding.registerMembers(f); - } - - @override - void checkTypes(SourceLibraryBuilder libraryBuilder, - TypeEnvironment typeEnvironment, SourcePropertyBuilder? setterBuilder) { - libraryBuilder.checkTypesInField(typeEnvironment, - isInstanceMember: builder.isDeclarationInstanceMember, - isLate: isLate, - isExternal: _fragment.modifiers.isExternal, - hasInitializer: hasInitializer, - fieldType: fieldType, - name: _fragment.name, - nameLength: _fragment.name.length, - nameOffset: nameOffset, - fileUri: fileUri); - } - - @override - void checkVariance( - SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) { - sourceClassBuilder.checkVarianceInField(typeEnvironment, - fieldType: fieldType, - isInstanceMember: !isStatic, - hasSetter: hasSetter, - isCovariantByDeclaration: _fragment.modifiers.isCovariant, - fileUri: fileUri, - fileOffset: nameOffset); - } - - @override - int computeDefaultTypes(ComputeDefaultTypeContext context) { - if (type is! OmittedTypeBuilder) { - context.reportInboundReferenceIssuesForType(type); - context.recursivelyReportGenericFunctionTypesAsBoundsForType(type); - } - return 0; - } - - @override - BodyBuilderContext createBodyBuilderContext() { - return new _FieldFragmentBodyBuilderContext( - this, _fragment, builder.libraryBuilder, builder.declarationBuilder, - isDeclarationInstanceMember: builder.isDeclarationInstanceMember); - } - - void createEncoding(SourcePropertyBuilder builder) { - SourceLibraryBuilder libraryBuilder = builder.libraryBuilder; - - bool isAbstract = _fragment.modifiers.isAbstract; - bool isExternal = _fragment.modifiers.isExternal; - bool isInstanceMember = builder.isDeclarationInstanceMember; - bool isExtensionMember = builder.isExtensionMember; - bool isExtensionTypeMember = builder.isExtensionTypeMember; - - // If in mixed mode, late lowerings cannot use `null` as a sentinel on - // non-nullable fields since they can be assigned from legacy code. - late_lowering.IsSetStrategy isSetStrategy = - late_lowering.computeIsSetStrategy(libraryBuilder); - if (isAbstract || isExternal) { - _encoding = new AbstractOrExternalFieldEncoding(_fragment, - isExtensionInstanceMember: isExtensionMember && isInstanceMember, - isExtensionTypeInstanceMember: - isExtensionTypeMember && isInstanceMember, - isAbstract: isAbstract, - isExternal: isExternal); - } else if (isExtensionTypeMember && isInstanceMember) { - if (_fragment.isPrimaryConstructorField) { - _encoding = new RepresentationFieldEncoding(_fragment); - } else { - // Field on a extension type. Encode as abstract. - // TODO(johnniwinther): Should we have an erroneous flag on such - // members? - _encoding = new AbstractOrExternalFieldEncoding(_fragment, - isExtensionInstanceMember: isExtensionMember && isInstanceMember, - isExtensionTypeInstanceMember: - isExtensionTypeMember && isInstanceMember, - isAbstract: true, - isExternal: false, - isForcedExtension: true); - } - } else if (isLate && - libraryBuilder.loader.target.backendTarget.isLateFieldLoweringEnabled( - hasInitializer: hasInitializer, - isFinal: isFinal, - isStatic: !isInstanceMember)) { - if (hasInitializer) { - if (isFinal) { - _encoding = new LateFinalFieldWithInitializerEncoding(_fragment, - isSetStrategy: isSetStrategy); - } else { - _encoding = new LateFieldWithInitializerEncoding(_fragment, - isSetStrategy: isSetStrategy); - } - } else { - if (isFinal) { - _encoding = new LateFinalFieldWithoutInitializerEncoding(_fragment, - isSetStrategy: isSetStrategy); - } else { - _encoding = new LateFieldWithoutInitializerEncoding(_fragment, - isSetStrategy: isSetStrategy); - } - } - } else if (libraryBuilder - .loader.target.backendTarget.useStaticFieldLowering && - !isInstanceMember && - !_fragment.modifiers.isConst && - hasInitializer) { - if (isFinal) { - _encoding = new LateFinalFieldWithInitializerEncoding(_fragment, - isSetStrategy: isSetStrategy); - } else { - _encoding = new LateFieldWithInitializerEncoding(_fragment, - isSetStrategy: isSetStrategy); - } - } else { - _encoding = new RegularFieldEncoding(_fragment, isEnumElement: false); - } - - type.registerInferredTypeListener(this); - Token? token = _fragment.initializerToken; - if (type is InferableTypeBuilder) { - if (!_fragment.modifiers.hasInitializer && isStatic) { - // A static field without type and initializer will always be inferred - // to have type `dynamic`. - type.registerInferredType(const DynamicType()); - } else { - // A field with no type and initializer or an instance field without - // type and initializer need to have the type inferred. - _encoding.type = new InferredType( - libraryBuilder: libraryBuilder, - typeBuilder: type, - inferType: inferType, - computeType: _computeInferredType, - fileUri: fileUri, - name: _fragment.name, - nameOffset: nameOffset, - nameLength: _fragment.name.length, - token: token); - type.registerInferable(this); - } - } - } - - @override - void ensureTypes( - ClassMembersBuilder membersBuilder, - Set<ClassMember>? getterOverrideDependencies, - Set<ClassMember>? setterOverrideDependencies) { - if (getterOverrideDependencies != null || - setterOverrideDependencies != null) { - membersBuilder.inferFieldType( - builder.declarationBuilder as SourceClassBuilder, - type, - [...?getterOverrideDependencies, ...?setterOverrideDependencies], - name: _fragment.name, - fileUri: fileUri, - nameOffset: nameOffset, - nameLength: _fragment.name.length, - isAssignable: hasSetter); - } else { - // Coverage-ignore-block(suite): Not run. - type.build(builder.libraryBuilder, TypeUse.fieldType, - hierarchy: membersBuilder.hierarchyBuilder); - } - } - - @override - Iterable<Reference> getExportedMemberReferences(FieldReference references) { - return [ - references.getterReference!, - if (hasSetter) references.setterReference! - ]; - } - - @override - void registerSuperCall() { - _encoding.registerSuperCall(); - } - - DartType _computeInferredType( - ClassHierarchyBase classHierarchy, Token? token) { - DartType? inferredType; - SourceLibraryBuilder libraryBuilder = builder.libraryBuilder; - DeclarationBuilder? declarationBuilder = builder.declarationBuilder; - if (token != null) { - InterfaceType? enclosingClassThisType = declarationBuilder - is SourceClassBuilder - ? libraryBuilder.loader.typeInferenceEngine.coreTypes - .thisInterfaceType( - declarationBuilder.cls, libraryBuilder.library.nonNullable) - : null; - LookupScope scope = _fragment.enclosingScope; - TypeInferrer typeInferrer = - libraryBuilder.loader.typeInferenceEngine.createTopLevelTypeInferrer( - fileUri, - enclosingClassThisType, - libraryBuilder, - scope, - builder - .dataForTesting - // Coverage-ignore(suite): Not run. - ?.inferenceData); - BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); - BodyBuilder bodyBuilder = libraryBuilder.loader.createBodyBuilderForField( - libraryBuilder, bodyBuilderContext, scope, typeInferrer, fileUri); - bodyBuilder.constantContext = _fragment.modifiers.isConst - ? ConstantContext.inferred - : ConstantContext.none; - bodyBuilder.inFieldInitializer = true; - bodyBuilder.inLateFieldInitializer = _fragment.modifiers.isLate; - Expression initializer = bodyBuilder.parseFieldInitializer(token); - - inferredType = - typeInferrer.inferImplicitFieldType(bodyBuilder, initializer); - } else { - inferredType = const DynamicType(); - } - return inferredType; - } - - @override - void _setCovariantByClassInternal() { - _encoding.setCovariantByClass(); - } -} - class FieldFragment implements Fragment { @override final String name; @@ -573,16 +117,3 @@ @override String toString() => '$runtimeType($name,$fileUri,$nameOffset)'; } - -abstract class FieldFragmentDeclaration { - bool get isStatic; - - void buildFieldInitializer(InferenceHelper helper, TypeInferrer typeInferrer, - CoreTypes coreTypes, Expression? initializer); - - BodyBuilderContext createBodyBuilderContext(); - - /// Registers that a `super` call has occurred in the initializer of this - /// field. - void registerSuperCall(); -}
diff --git a/pkg/front_end/lib/src/fragment/field/body_builder_context.dart b/pkg/front_end/lib/src/fragment/field/body_builder_context.dart index d9027f3..f666aa1 100644 --- a/pkg/front_end/lib/src/fragment/field/body_builder_context.dart +++ b/pkg/front_end/lib/src/fragment/field/body_builder_context.dart
@@ -4,11 +4,11 @@ part of '../fragment.dart'; -class _FieldFragmentBodyBuilderContext extends BodyBuilderContext { +class FieldFragmentBodyBuilderContext extends BodyBuilderContext { final FieldFragmentDeclaration _declaration; final FieldFragment _fragment; - _FieldFragmentBodyBuilderContext( + FieldFragmentBodyBuilderContext( this._declaration, this._fragment, SourceLibraryBuilder libraryBuilder,
diff --git a/pkg/front_end/lib/src/fragment/field/declaration.dart b/pkg/front_end/lib/src/fragment/field/declaration.dart new file mode 100644 index 0000000..3a235b4 --- /dev/null +++ b/pkg/front_end/lib/src/fragment/field/declaration.dart
@@ -0,0 +1,716 @@ +// Copyright (c) 2025, 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:_fe_analyzer_shared/src/metadata/expressions.dart' as shared; +import 'package:_fe_analyzer_shared/src/scanner/scanner.dart' show Token; +import 'package:kernel/ast.dart'; +import 'package:kernel/class_hierarchy.dart'; +import 'package:kernel/core_types.dart'; +import 'package:kernel/type_environment.dart'; + +import '../../base/constant_context.dart'; +import '../../base/messages.dart'; +import '../../base/problems.dart'; +import '../../base/scope.dart'; +import '../../builder/declaration_builders.dart'; +import '../../builder/metadata_builder.dart'; +import '../../builder/omitted_type_builder.dart'; +import '../../builder/property_builder.dart'; +import '../../builder/type_builder.dart'; +import '../../kernel/body_builder.dart'; +import '../../kernel/body_builder_context.dart'; +import '../../kernel/hierarchy/class_member.dart'; +import '../../kernel/hierarchy/members_builder.dart'; +import '../../kernel/implicit_field_type.dart'; +import '../../kernel/late_lowering.dart' as late_lowering; +import '../../kernel/macro/metadata.dart'; +import '../../kernel/type_algorithms.dart'; +import '../../source/name_scheme.dart'; +import '../../source/source_class_builder.dart'; +import '../../source/source_library_builder.dart'; +import '../../source/source_member_builder.dart'; +import '../../source/source_property_builder.dart'; +import '../../type_inference/inference_helper.dart'; +import '../../type_inference/type_inference_engine.dart'; +import '../../type_inference/type_inferrer.dart'; +import '../fragment.dart'; + +/// Common interface for fragments that can declare a field. +abstract class FieldDeclaration { + FieldQuality get fieldQuality; + + GetterQuality get getterQuality; + + SetterQuality get setterQuality; + + /// The metadata declared on this fragment. + List<MetadataBuilder>? get metadata; + + /// Builds the core AST structures for this field declaration as needed for + /// the outline. + void buildOutlineNode(SourceLibraryBuilder libraryBuilder, + NameScheme nameScheme, BuildNodesCallback f, FieldReference references, + {required List<TypeParameter>? classTypeParameters}); + + void buildOutlineExpressions( + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required List<Annotatable> annotatables, + required Uri annotatablesFileUri, + required bool isClassInstanceMember}); + + int computeDefaultTypes(ComputeDefaultTypeContext context); + + void checkTypes(SourceLibraryBuilder libraryBuilder, + TypeEnvironment typeEnvironment, SourcePropertyBuilder? setterBuilder); + + /// Checks the variance of type parameters [sourceClassBuilder] used in the + /// type of this field declaration. + void checkVariance( + SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment); + + /// The references to the members from this field declaration that are + /// accessible in exports through the name of the builder. + Iterable<Reference> getExportedMemberReferences(FieldReference references); + + /// Return `true` if the declaration introduces a setter. + bool get hasSetter; + + /// Return `true` if the declaration has an initializer. + bool get hasInitializer; + + /// Return `true` if the declaration is final. + bool get isFinal; + + /// Return `true` if the declaration is late. + bool get isLate; + + /// Return `true` if the declaration is in instance field declared in an + /// extension type. + bool get isExtensionTypeDeclaredInstanceField; + + /// Returns `true` if this field is declared by an enum element. + bool get isEnumElement; + + /// The [ClassMember]s for the getter introduced by this field declaration. + List<ClassMember> get localMembers; + + /// The [ClassMember]s for the setter introduced by this field declaration, + /// if any. + List<ClassMember> get localSetters; + + /// The [Member] uses as the target for reading from this field declaration. + Member get readTarget; + + /// The [Member] uses as the target for writing to this field declaration, or + /// `null` if this field declaration has no setter. + Member? get writeTarget; + + /// The [DartType] of this field declaration. + abstract DartType fieldType; + + /// Creates the [Initializer] for the invalid initialization of this field. + /// + /// This is only used for instance fields. + Initializer buildErroneousInitializer(Expression effect, Expression value, + {required int fileOffset}); + + /// Creates the AST node for this field as the default initializer. + /// + /// This is only used for instance fields. + void buildImplicitDefaultValue(); + + /// Creates the [Initializer] for the implicit initialization of this field + /// in a constructor. + /// + /// This is only used for instance fields. + Initializer buildImplicitInitializer(); + + /// Builds the [Initializer]s for each field used to encode this field + /// using the [fileOffset] for the created nodes and [value] as the initial + /// field value. + /// + /// This is only used for instance fields. + List<Initializer> buildInitializer(int fileOffset, Expression value, + {required bool isSynthetic}); + + /// Ensures that the type of this field declaration has been computed. + void ensureTypes( + ClassMembersBuilder membersBuilder, + Set<ClassMember>? getterOverrideDependencies, + Set<ClassMember>? setterOverrideDependencies); + + /// Infers the type of this field declaration. + DartType inferType(ClassHierarchyBase hierarchy); + + shared.Expression? get initializerExpression; +} + +class FieldDeclarationImpl + with FieldDeclarationMixin + implements + FieldDeclaration, + FieldFragmentDeclaration, + Inferable, + InferredTypeListener { + final FieldFragment _fragment; + + late final FieldEncoding _encoding; + + shared.Expression? _initializerExpression; + + /// Whether the body of this field has been built. + /// + /// Constant fields have their initializer built in the outline so we avoid + /// building them twice as part of the non-outline build. + bool hasBodyBeenBuilt = false; + + FieldDeclarationImpl(this._fragment) { + _fragment.declaration = this; + } + + @override + SourcePropertyBuilder get builder => _fragment.builder; + + @override + FieldQuality get fieldQuality => _fragment.modifiers.isAbstract + ? FieldQuality.Abstract + : _fragment.modifiers.isExternal + ? FieldQuality.External + : FieldQuality.Concrete; + + @override + DartType get fieldType => _encoding.type; + + @override + Uri get fileUri => _fragment.fileUri; + + @override + GetterQuality get getterQuality => _fragment.modifiers.isAbstract + ? GetterQuality.ImplicitAbstract + : _fragment.modifiers.isExternal + ? GetterQuality.ImplicitExternal + : GetterQuality.Implicit; + + @override + bool get hasInitializer => _fragment.modifiers.hasInitializer; + + @override + bool get hasSetter => _fragment.hasSetter; + + @override + // Coverage-ignore(suite): Not run. + shared.Expression? get initializerExpression => _initializerExpression; + + @override + bool get isConst => _fragment.modifiers.isConst; + + @override + bool get isEnumElement => false; + + @override + bool get isExtensionTypeDeclaredInstanceField => + builder.isExtensionTypeInstanceMember && + !_fragment.isPrimaryConstructorField; + + @override + bool get isFinal => _fragment.modifiers.isFinal; + + @override + bool get isLate => _fragment.modifiers.isLate; + + @override + bool get isStatic => + _fragment.modifiers.isStatic || builder.declarationBuilder == null; + + @override + List<ClassMember> get localMembers => _encoding.localMembers; + + @override + List<ClassMember> get localSetters => _encoding.localSetters; + + @override + List<MetadataBuilder>? get metadata => _fragment.metadata; + + @override + int get nameOffset => _fragment.nameOffset; + + @override + Member get readTarget => _encoding.readTarget; + + @override + SetterQuality get setterQuality => !hasSetter + ? SetterQuality.Absent + : _fragment.modifiers.isAbstract + ? SetterQuality.ImplicitAbstract + : _fragment.modifiers.isExternal + ? SetterQuality.ImplicitExternal + : SetterQuality.Implicit; + + @override + TypeBuilder get type => _fragment.type; + + @override + Member? get writeTarget => _encoding.writeTarget; + + @override + // Coverage-ignore(suite): Not run. + DartType get fieldTypeInternal => _encoding.type; + + @override + void set fieldTypeInternal(DartType value) { + _encoding.type = value; + } + + /// Builds the body of this field using [initializer] as the initializer + /// expression. + void buildBody(CoreTypes coreTypes, Expression? initializer) { + assert(!hasBodyBeenBuilt, "Body has already been built for $this."); + hasBodyBeenBuilt = true; + if (!_fragment.modifiers.hasInitializer && + initializer != null && + initializer is! NullLiteral && + // Coverage-ignore(suite): Not run. + !_fragment.modifiers.isConst && + // Coverage-ignore(suite): Not run. + !_fragment.modifiers.isFinal) { + internalProblem( + messageInternalProblemAlreadyInitialized, nameOffset, fileUri); + } + _encoding.createBodies(coreTypes, initializer); + } + + @override + Initializer buildErroneousInitializer(Expression effect, Expression value, + {required int fileOffset}) { + return _encoding.buildErroneousInitializer(effect, value, + fileOffset: fileOffset); + } + + @override + void buildFieldInitializer(InferenceHelper helper, TypeInferrer typeInferrer, + CoreTypes coreTypes, Expression? initializer) { + if (initializer != null) { + if (!hasBodyBeenBuilt) { + initializer = typeInferrer + .inferFieldInitializer(helper, fieldType, initializer) + .expression; + buildBody(coreTypes, initializer); + } + } else if (!hasBodyBeenBuilt) { + buildBody(coreTypes, null); + } + } + + @override + void buildImplicitDefaultValue() { + _encoding.buildImplicitDefaultValue(); + } + + @override + Initializer buildImplicitInitializer() { + return _encoding.buildImplicitInitializer(); + } + + @override + List<Initializer> buildInitializer(int fileOffset, Expression value, + {required bool isSynthetic}) { + return _encoding.createInitializer(fileOffset, value, + isSynthetic: isSynthetic); + } + + @override + void buildOutlineExpressions( + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required List<Annotatable> annotatables, + required Uri annotatablesFileUri, + required bool isClassInstanceMember}) { + BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); + for (Annotatable annotatable in annotatables) { + buildMetadataForOutlineExpressions( + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope, + bodyBuilderContext: bodyBuilderContext, + annotatable: annotatable, + annotatableFileUri: annotatablesFileUri, + metadata: metadata); + } + // For modular compilation we need to include initializers of all const + // fields and all non-static final fields in classes with const constructors + // into the outline. + Token? token = _fragment.constInitializerToken; + if ((_fragment.modifiers.isConst || + (isFinal && + isClassInstanceMember && + (declarationBuilder as SourceClassBuilder) + .declaresConstConstructor)) && + token != null) { + LookupScope scope = _fragment.enclosingScope; + BodyBuilder bodyBuilder = libraryBuilder.loader + .createBodyBuilderForOutlineExpression( + libraryBuilder, createBodyBuilderContext(), scope, fileUri); + bodyBuilder.constantContext = _fragment.modifiers.isConst + ? ConstantContext.inferred + : ConstantContext.required; + Expression initializer = bodyBuilder.typeInferrer + .inferFieldInitializer( + bodyBuilder, fieldType, bodyBuilder.parseFieldInitializer(token)) + .expression; + buildBody(classHierarchy.coreTypes, initializer); + bodyBuilder.performBacklogComputations(); + if (computeSharedExpressionForTesting) { + // Coverage-ignore-block(suite): Not run. + _initializerExpression = parseFieldInitializer(libraryBuilder.loader, + token, libraryBuilder.importUri, fileUri, scope); + } + } + } + + @override + void buildOutlineNode(SourceLibraryBuilder libraryBuilder, + NameScheme nameScheme, BuildNodesCallback f, FieldReference references, + {required List<TypeParameter>? classTypeParameters}) { + _encoding.buildOutlineNode(libraryBuilder, nameScheme, references, + isAbstractOrExternal: + _fragment.modifiers.isAbstract || _fragment.modifiers.isExternal, + classTypeParameters: classTypeParameters); + if (type is! InferableTypeBuilder) { + fieldType = type.build(libraryBuilder, TypeUse.fieldType); + } + _encoding.registerMembers(f); + } + + @override + void checkTypes(SourceLibraryBuilder libraryBuilder, + TypeEnvironment typeEnvironment, SourcePropertyBuilder? setterBuilder) { + libraryBuilder.checkTypesInField(typeEnvironment, + isInstanceMember: builder.isDeclarationInstanceMember, + isLate: isLate, + isExternal: _fragment.modifiers.isExternal, + hasInitializer: hasInitializer, + fieldType: fieldType, + name: _fragment.name, + nameLength: _fragment.name.length, + nameOffset: nameOffset, + fileUri: fileUri); + } + + @override + void checkVariance( + SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment) { + sourceClassBuilder.checkVarianceInField(typeEnvironment, + fieldType: fieldType, + isInstanceMember: !isStatic, + hasSetter: hasSetter, + isCovariantByDeclaration: _fragment.modifiers.isCovariant, + fileUri: fileUri, + fileOffset: nameOffset); + } + + @override + int computeDefaultTypes(ComputeDefaultTypeContext context) { + if (type is! OmittedTypeBuilder) { + context.reportInboundReferenceIssuesForType(type); + context.recursivelyReportGenericFunctionTypesAsBoundsForType(type); + } + return 0; + } + + @override + BodyBuilderContext createBodyBuilderContext() { + return new FieldFragmentBodyBuilderContext( + this, _fragment, builder.libraryBuilder, builder.declarationBuilder, + isDeclarationInstanceMember: builder.isDeclarationInstanceMember); + } + + void createEncoding(SourcePropertyBuilder builder) { + SourceLibraryBuilder libraryBuilder = builder.libraryBuilder; + + bool isAbstract = _fragment.modifiers.isAbstract; + bool isExternal = _fragment.modifiers.isExternal; + bool isInstanceMember = builder.isDeclarationInstanceMember; + bool isExtensionMember = builder.isExtensionMember; + bool isExtensionTypeMember = builder.isExtensionTypeMember; + + // If in mixed mode, late lowerings cannot use `null` as a sentinel on + // non-nullable fields since they can be assigned from legacy code. + late_lowering.IsSetStrategy isSetStrategy = + late_lowering.computeIsSetStrategy(libraryBuilder); + if (isAbstract || isExternal) { + _encoding = new AbstractOrExternalFieldEncoding(_fragment, + isExtensionInstanceMember: isExtensionMember && isInstanceMember, + isExtensionTypeInstanceMember: + isExtensionTypeMember && isInstanceMember, + isAbstract: isAbstract, + isExternal: isExternal); + } else if (isExtensionTypeMember && isInstanceMember) { + if (_fragment.isPrimaryConstructorField) { + _encoding = new RepresentationFieldEncoding(_fragment); + } else { + // Field on a extension type. Encode as abstract. + // TODO(johnniwinther): Should we have an erroneous flag on such + // members? + _encoding = new AbstractOrExternalFieldEncoding(_fragment, + isExtensionInstanceMember: isExtensionMember && isInstanceMember, + isExtensionTypeInstanceMember: + isExtensionTypeMember && isInstanceMember, + isAbstract: true, + isExternal: false, + isForcedExtension: true); + } + } else if (isLate && + libraryBuilder.loader.target.backendTarget.isLateFieldLoweringEnabled( + hasInitializer: hasInitializer, + isFinal: isFinal, + isStatic: !isInstanceMember)) { + if (hasInitializer) { + if (isFinal) { + _encoding = new LateFinalFieldWithInitializerEncoding(_fragment, + isSetStrategy: isSetStrategy); + } else { + _encoding = new LateFieldWithInitializerEncoding(_fragment, + isSetStrategy: isSetStrategy); + } + } else { + if (isFinal) { + _encoding = new LateFinalFieldWithoutInitializerEncoding(_fragment, + isSetStrategy: isSetStrategy); + } else { + _encoding = new LateFieldWithoutInitializerEncoding(_fragment, + isSetStrategy: isSetStrategy); + } + } + } else if (libraryBuilder + .loader.target.backendTarget.useStaticFieldLowering && + !isInstanceMember && + !_fragment.modifiers.isConst && + hasInitializer) { + if (isFinal) { + _encoding = new LateFinalFieldWithInitializerEncoding(_fragment, + isSetStrategy: isSetStrategy); + } else { + _encoding = new LateFieldWithInitializerEncoding(_fragment, + isSetStrategy: isSetStrategy); + } + } else { + _encoding = new RegularFieldEncoding(_fragment, isEnumElement: false); + } + + type.registerInferredTypeListener(this); + Token? token = _fragment.initializerToken; + if (type is InferableTypeBuilder) { + if (!_fragment.modifiers.hasInitializer && isStatic) { + // A static field without type and initializer will always be inferred + // to have type `dynamic`. + type.registerInferredType(const DynamicType()); + } else { + // A field with no type and initializer or an instance field without + // type and initializer need to have the type inferred. + _encoding.type = new InferredType( + libraryBuilder: libraryBuilder, + typeBuilder: type, + inferType: inferType, + computeType: _computeInferredType, + fileUri: fileUri, + name: _fragment.name, + nameOffset: nameOffset, + nameLength: _fragment.name.length, + token: token); + type.registerInferable(this); + } + } + } + + @override + void ensureTypes( + ClassMembersBuilder membersBuilder, + Set<ClassMember>? getterOverrideDependencies, + Set<ClassMember>? setterOverrideDependencies) { + if (getterOverrideDependencies != null || + setterOverrideDependencies != null) { + membersBuilder.inferFieldType( + builder.declarationBuilder as SourceClassBuilder, + type, + [...?getterOverrideDependencies, ...?setterOverrideDependencies], + name: _fragment.name, + fileUri: fileUri, + nameOffset: nameOffset, + nameLength: _fragment.name.length, + isAssignable: hasSetter); + } else { + // Coverage-ignore-block(suite): Not run. + type.build(builder.libraryBuilder, TypeUse.fieldType, + hierarchy: membersBuilder.hierarchyBuilder); + } + } + + @override + Iterable<Reference> getExportedMemberReferences(FieldReference references) { + return [ + references.getterReference!, + if (hasSetter) references.setterReference! + ]; + } + + @override + void registerSuperCall() { + _encoding.registerSuperCall(); + } + + DartType _computeInferredType( + ClassHierarchyBase classHierarchy, Token? token) { + DartType? inferredType; + SourceLibraryBuilder libraryBuilder = builder.libraryBuilder; + DeclarationBuilder? declarationBuilder = builder.declarationBuilder; + if (token != null) { + InterfaceType? enclosingClassThisType = declarationBuilder + is SourceClassBuilder + ? libraryBuilder.loader.typeInferenceEngine.coreTypes + .thisInterfaceType( + declarationBuilder.cls, libraryBuilder.library.nonNullable) + : null; + LookupScope scope = _fragment.enclosingScope; + TypeInferrer typeInferrer = + libraryBuilder.loader.typeInferenceEngine.createTopLevelTypeInferrer( + fileUri, + enclosingClassThisType, + libraryBuilder, + scope, + builder + .dataForTesting + // Coverage-ignore(suite): Not run. + ?.inferenceData); + BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); + BodyBuilder bodyBuilder = libraryBuilder.loader.createBodyBuilderForField( + libraryBuilder, bodyBuilderContext, scope, typeInferrer, fileUri); + bodyBuilder.constantContext = _fragment.modifiers.isConst + ? ConstantContext.inferred + : ConstantContext.none; + bodyBuilder.inFieldInitializer = true; + bodyBuilder.inLateFieldInitializer = _fragment.modifiers.isLate; + Expression initializer = bodyBuilder.parseFieldInitializer(token); + + inferredType = + typeInferrer.inferImplicitFieldType(bodyBuilder, initializer); + } else { + inferredType = const DynamicType(); + } + return inferredType; + } + + @override + void setCovariantByClassInternal() { + _encoding.setCovariantByClass(); + } +} + +mixin FieldDeclarationMixin + implements FieldDeclaration, Inferable, InferredTypeListener { + Uri get fileUri; + + int get nameOffset; + + SourcePropertyBuilder get builder; + + bool get isConst; + + /// The [TypeBuilder] for the declared type of this field declaration. + TypeBuilder get type; + + void setCovariantByClassInternal(); + + abstract DartType fieldTypeInternal; + + @override + void onInferredType(DartType type) { + fieldType = type; + } + + @override + void inferTypes(ClassHierarchyBase hierarchy) { + inferType(hierarchy); + } + + @override + DartType inferType(ClassHierarchyBase hierarchy) { + if (fieldType is! InferredType) { + // We have already inferred a type. + return fieldType; + } + + return builder.libraryBuilder.loader + .withUriForCrashReporting(fileUri, nameOffset, () { + InferredType implicitFieldType = fieldType as InferredType; + DartType inferredType = implicitFieldType.computeType(hierarchy); + if (fieldType is InferredType) { + // `fieldType` may have changed if a circularity was detected when + // [inferredType] was computed. + type.registerInferredType(inferredType); + + // TODO(johnniwinther): Isn't this handled in the [fieldType] setter? + IncludesTypeParametersNonCovariantly? needsCheckVisitor; + DeclarationBuilder? declarationBuilder = builder.declarationBuilder; + if (declarationBuilder is ClassBuilder) { + Class enclosingClass = declarationBuilder.cls; + if (enclosingClass.typeParameters.isNotEmpty) { + needsCheckVisitor = new IncludesTypeParametersNonCovariantly( + enclosingClass.typeParameters, + // We are checking the field type as if it is the type of the + // parameter of the implicit setter and this is a contravariant + // position. + initialVariance: Variance.contravariant); + } + } + if (needsCheckVisitor != null) { + if (fieldType.accept(needsCheckVisitor)) { + setCovariantByClassInternal(); + } + } + } + return fieldType; + }); + } + + @override + // Coverage-ignore(suite): Not run. + DartType get fieldType => fieldTypeInternal; + + @override + void set fieldType(DartType value) { + fieldTypeInternal = value; + DeclarationBuilder? declarationBuilder = builder.declarationBuilder; + // TODO(johnniwinther): Should this be `hasSetter`? + if (!isFinal && !isConst && declarationBuilder is ClassBuilder) { + Class enclosingClass = declarationBuilder.cls; + if (enclosingClass.typeParameters.isNotEmpty) { + IncludesTypeParametersNonCovariantly needsCheckVisitor = + new IncludesTypeParametersNonCovariantly( + enclosingClass.typeParameters, + // We are checking the field type as if it is the type of the + // parameter of the implicit setter and this is a contravariant + // position. + initialVariance: Variance.contravariant); + if (value.accept(needsCheckVisitor)) { + setCovariantByClassInternal(); + } + } + } + } +} + +abstract class FieldFragmentDeclaration { + bool get isStatic; + + void buildFieldInitializer(InferenceHelper helper, TypeInferrer typeInferrer, + CoreTypes coreTypes, Expression? initializer); + + BodyBuilderContext createBodyBuilderContext(); + + /// Registers that a `super` call has occurred in the initializer of this + /// field. + void registerSuperCall(); +}
diff --git a/pkg/front_end/lib/src/fragment/field/encoding.dart b/pkg/front_end/lib/src/fragment/field/encoding.dart index c5de38e..b14502a 100644 --- a/pkg/front_end/lib/src/fragment/field/encoding.dart +++ b/pkg/front_end/lib/src/fragment/field/encoding.dart
@@ -8,7 +8,7 @@ /// /// This is used to provide lowerings for late fields using synthesized getters /// and setters. -sealed class _FieldEncoding { +sealed class FieldEncoding { /// Creates the members necessary for this field encoding. /// /// This method is called for both outline and full compilation so the created @@ -100,7 +100,7 @@ void registerSuperCall(); } -class RegularFieldEncoding implements _FieldEncoding { +class RegularFieldEncoding implements FieldEncoding { final FieldFragment _fragment; final bool isEnumElement; Field? _field; @@ -269,7 +269,7 @@ } } -abstract class AbstractLateFieldEncoding implements _FieldEncoding { +abstract class AbstractLateFieldEncoding implements FieldEncoding { final FieldFragment _fragment; DartType? _type; Field? _field; @@ -849,7 +849,7 @@ } } -class AbstractOrExternalFieldEncoding implements _FieldEncoding { +class AbstractOrExternalFieldEncoding implements FieldEncoding { final FieldFragment _fragment; final bool isAbstract; final bool isExternal; @@ -1191,7 +1191,7 @@ } /// The encoding of an extension type declaration representation field. -class RepresentationFieldEncoding implements _FieldEncoding { +class RepresentationFieldEncoding implements FieldEncoding { final FieldFragment _fragment; late Procedure _getter;
diff --git a/pkg/front_end/lib/src/fragment/fragment.dart b/pkg/front_end/lib/src/fragment/fragment.dart index 1a6b448..1322275 100644 --- a/pkg/front_end/lib/src/fragment/fragment.dart +++ b/pkg/front_end/lib/src/fragment/fragment.dart
@@ -17,7 +17,6 @@ import '../base/local_scope.dart'; import '../base/messages.dart'; import '../base/modifiers.dart'; -import '../base/problems.dart'; import '../base/scope.dart'; import '../builder/builder.dart'; import '../builder/constructor_reference_builder.dart'; @@ -40,7 +39,6 @@ import '../kernel/implicit_field_type.dart'; import '../kernel/internal_ast.dart'; import '../kernel/late_lowering.dart' as late_lowering; -import '../kernel/macro/metadata.dart'; import '../kernel/member_covariance.dart'; import '../kernel/type_algorithms.dart'; import '../source/builder_factory.dart'; @@ -58,13 +56,12 @@ import '../source/source_type_alias_builder.dart'; import '../source/source_type_parameter_builder.dart'; import '../source/type_parameter_scope_builder.dart'; -import '../type_inference/inference_helper.dart'; import '../type_inference/inference_results.dart'; import '../type_inference/type_inference_engine.dart'; -import '../type_inference/type_inferrer.dart'; import '../type_inference/type_schema.dart'; import 'constructor/declaration.dart'; import 'factory/declaration.dart'; +import 'field/declaration.dart'; import 'getter/declaration.dart'; import 'getter/encoding.dart'; import 'method/declaration.dart';
diff --git a/pkg/front_end/lib/src/fragment/getter/declaration.dart b/pkg/front_end/lib/src/fragment/getter/declaration.dart index 1b4c029..9ed821c 100644 --- a/pkg/front_end/lib/src/fragment/getter/declaration.dart +++ b/pkg/front_end/lib/src/fragment/getter/declaration.dart
@@ -44,8 +44,8 @@ required DeclarationBuilder? declarationBuilder, required SourcePropertyBuilder propertyBuilder, required Annotatable annotatable, - required bool isClassInstanceMember, - required bool createFileUriExpression}); + required Uri annotatableFileUri, + required bool isClassInstanceMember}); void buildOutlineNode( {required SourceLibraryBuilder libraryBuilder, @@ -90,6 +90,7 @@ AsyncMarker get asyncModifier => _fragment.asyncModifier; @override + // Coverage-ignore(suite): Not run. Uri get fileUri => _fragment.fileUri; @override @@ -142,16 +143,16 @@ required DeclarationBuilder? declarationBuilder, required SourcePropertyBuilder propertyBuilder, required Annotatable annotatable, - required bool isClassInstanceMember, - required bool createFileUriExpression}) { + required Uri annotatableFileUri, + required bool isClassInstanceMember}) { _encoding.buildOutlineExpressions( - classHierarchy, - libraryBuilder, - declarationBuilder, - createBodyBuilderContext(propertyBuilder), - annotatable, - isClassInstanceMember: isClassInstanceMember, - createFileUriExpression: createFileUriExpression); + classHierarchy: classHierarchy, + libraryBuilder: libraryBuilder, + declarationBuilder: declarationBuilder, + bodyBuilderContext: createBodyBuilderContext(propertyBuilder), + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + isClassInstanceMember: isClassInstanceMember); } @override
diff --git a/pkg/front_end/lib/src/fragment/getter/encoding.dart b/pkg/front_end/lib/src/fragment/getter/encoding.dart index f5aa70b..427e47b 100644 --- a/pkg/front_end/lib/src/fragment/getter/encoding.dart +++ b/pkg/front_end/lib/src/fragment/getter/encoding.dart
@@ -121,13 +121,13 @@ void becomeNative(SourceLoader loader); void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - BodyBuilderContext bodyBuilderContext, - Annotatable annotatable, - {required bool isClassInstanceMember, - required bool createFileUriExpression}); + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required BodyBuilderContext bodyBuilderContext, + required Annotatable annotatable, + required Uri annotatableFileUri, + required bool isClassInstanceMember}); void buildOutlineNode( {required SourceLibraryBuilder libraryBuilder, @@ -211,17 +211,20 @@ @override void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - BodyBuilderContext bodyBuilderContext, - Annotatable annotatable, - {required bool isClassInstanceMember, - required bool createFileUriExpression}) { - buildMetadataForOutlineExpressions(libraryBuilder, _fragment.enclosingScope, - bodyBuilderContext, annotatable, _fragment.metadata, - fileUri: _fragment.fileUri, - createFileUriExpression: createFileUriExpression); + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required BodyBuilderContext bodyBuilderContext, + required Annotatable annotatable, + required Uri annotatableFileUri, + required bool isClassInstanceMember}) { + buildMetadataForOutlineExpressions( + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope, + bodyBuilderContext: bodyBuilderContext, + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + metadata: _fragment.metadata); buildTypeParametersForOutlineExpressions( classHierarchy, libraryBuilder, @@ -429,17 +432,20 @@ @override void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - BodyBuilderContext bodyBuilderContext, - Annotatable annotatable, - {required bool isClassInstanceMember, - required bool createFileUriExpression}) { - buildMetadataForOutlineExpressions(libraryBuilder, _fragment.enclosingScope, - bodyBuilderContext, annotatable, _fragment.metadata, - fileUri: _fragment.fileUri, - createFileUriExpression: createFileUriExpression); + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required BodyBuilderContext bodyBuilderContext, + required Annotatable annotatable, + required Uri annotatableFileUri, + required bool isClassInstanceMember}) { + buildMetadataForOutlineExpressions( + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope, + bodyBuilderContext: bodyBuilderContext, + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + metadata: _fragment.metadata); buildTypeParametersForOutlineExpressions( classHierarchy,
diff --git a/pkg/front_end/lib/src/fragment/method/declaration.dart b/pkg/front_end/lib/src/fragment/method/declaration.dart index effc03f..cdc4d89 100644 --- a/pkg/front_end/lib/src/fragment/method/declaration.dart +++ b/pkg/front_end/lib/src/fragment/method/declaration.dart
@@ -43,13 +43,13 @@ Procedure? get readTarget; void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - SourceMethodBuilder methodBuilder, - Annotatable annotatable, - {required bool isClassInstanceMember, - required bool createFileUriExpression}); + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required SourceMethodBuilder methodBuilder, + required Annotatable annotatable, + required Uri annotatableFileUri, + required bool isClassInstanceMember}); void buildOutlineNode(SourceLibraryBuilder libraryBuilder, NameScheme nameScheme, BuildNodesCallback f, @@ -125,21 +125,21 @@ @override void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - SourceMethodBuilder methodBuilder, - Annotatable annotatable, - {required bool isClassInstanceMember, - required bool createFileUriExpression}) { + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required SourceMethodBuilder methodBuilder, + required Annotatable annotatable, + required Uri annotatableFileUri, + required bool isClassInstanceMember}) { _encoding.buildOutlineExpressions( - classHierarchy, - libraryBuilder, - declarationBuilder, - createBodyBuilderContext(methodBuilder), - annotatable, - isClassInstanceMember: isClassInstanceMember, - createFileUriExpression: createFileUriExpression); + classHierarchy: classHierarchy, + libraryBuilder: libraryBuilder, + declarationBuilder: declarationBuilder, + bodyBuilderContext: createBodyBuilderContext(methodBuilder), + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + isClassInstanceMember: isClassInstanceMember); } @override
diff --git a/pkg/front_end/lib/src/fragment/method/encoding.dart b/pkg/front_end/lib/src/fragment/method/encoding.dart index 7f2fdd9..ddeacaf 100644 --- a/pkg/front_end/lib/src/fragment/method/encoding.dart +++ b/pkg/front_end/lib/src/fragment/method/encoding.dart
@@ -42,13 +42,13 @@ void becomeNative(SourceLoader loader); void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - BodyBuilderContext bodyBuilderContext, - Annotatable annotatable, - {required bool isClassInstanceMember, - required bool createFileUriExpression}); + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required BodyBuilderContext bodyBuilderContext, + required Annotatable annotatable, + required Uri annotatableFileUri, + required bool isClassInstanceMember}); void buildOutlineNode(SourceLibraryBuilder libraryBuilder, NameScheme nameScheme, BuildNodesCallback f, @@ -145,17 +145,20 @@ @override void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - BodyBuilderContext bodyBuilderContext, - Annotatable annotatable, - {required bool isClassInstanceMember, - required bool createFileUriExpression}) { - buildMetadataForOutlineExpressions(libraryBuilder, _fragment.enclosingScope, - bodyBuilderContext, annotatable, _fragment.metadata, - fileUri: _fragment.fileUri, - createFileUriExpression: createFileUriExpression); + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required BodyBuilderContext bodyBuilderContext, + required Annotatable annotatable, + required Uri annotatableFileUri, + required bool isClassInstanceMember}) { + buildMetadataForOutlineExpressions( + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope, + bodyBuilderContext: bodyBuilderContext, + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + metadata: _fragment.metadata); buildTypeParametersForOutlineExpressions(classHierarchy, libraryBuilder, bodyBuilderContext, _fragment.declaredTypeParameters?.builders); buildFormalsForOutlineExpressions( @@ -386,17 +389,20 @@ @override void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - BodyBuilderContext bodyBuilderContext, - Annotatable annotatable, - {required bool isClassInstanceMember, - required bool createFileUriExpression}) { - buildMetadataForOutlineExpressions(libraryBuilder, _fragment.enclosingScope, - bodyBuilderContext, annotatable, _fragment.metadata, - fileUri: _fragment.fileUri, - createFileUriExpression: createFileUriExpression); + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required BodyBuilderContext bodyBuilderContext, + required Annotatable annotatable, + required Uri annotatableFileUri, + required bool isClassInstanceMember}) { + buildMetadataForOutlineExpressions( + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope, + bodyBuilderContext: bodyBuilderContext, + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + metadata: _fragment.metadata); buildTypeParametersForOutlineExpressions(classHierarchy, libraryBuilder, bodyBuilderContext, _fragment.declaredTypeParameters?.builders);
diff --git a/pkg/front_end/lib/src/fragment/setter/declaration.dart b/pkg/front_end/lib/src/fragment/setter/declaration.dart index dd2dbae..1dbd655 100644 --- a/pkg/front_end/lib/src/fragment/setter/declaration.dart +++ b/pkg/front_end/lib/src/fragment/setter/declaration.dart
@@ -44,8 +44,8 @@ required DeclarationBuilder? declarationBuilder, required SourcePropertyBuilder propertyBuilder, required Annotatable annotatable, - required bool isClassInstanceMember, - required bool createFileUriExpression}); + required Uri annotatableFileUri, + required bool isClassInstanceMember}); void buildOutlineNode( {required SourceLibraryBuilder libraryBuilder, @@ -90,6 +90,7 @@ AsyncMarker get asyncModifier => _fragment.asyncModifier; @override + // Coverage-ignore(suite): Not run. Uri get fileUri => _fragment.fileUri; @override @@ -146,16 +147,16 @@ required DeclarationBuilder? declarationBuilder, required SourcePropertyBuilder propertyBuilder, required Annotatable annotatable, - required bool isClassInstanceMember, - required bool createFileUriExpression}) { + required Uri annotatableFileUri, + required bool isClassInstanceMember}) { _encoding.buildOutlineExpressions( - classHierarchy, - libraryBuilder, - declarationBuilder, - createBodyBuilderContext(propertyBuilder), - annotatable, - isClassInstanceMember: isClassInstanceMember, - createFileUriExpression: createFileUriExpression); + classHierarchy: classHierarchy, + libraryBuilder: libraryBuilder, + declarationBuilder: declarationBuilder, + bodyBuilderContext: createBodyBuilderContext(propertyBuilder), + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + isClassInstanceMember: isClassInstanceMember); } @override
diff --git a/pkg/front_end/lib/src/fragment/setter/encoding.dart b/pkg/front_end/lib/src/fragment/setter/encoding.dart index f7f5e2b..a5b3fca 100644 --- a/pkg/front_end/lib/src/fragment/setter/encoding.dart +++ b/pkg/front_end/lib/src/fragment/setter/encoding.dart
@@ -139,13 +139,13 @@ void becomeNative(SourceLoader loader); void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - BodyBuilderContext bodyBuilderContext, - Annotatable annotatable, - {required bool isClassInstanceMember, - required bool createFileUriExpression}); + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required BodyBuilderContext bodyBuilderContext, + required Annotatable annotatable, + required Uri annotatableFileUri, + required bool isClassInstanceMember}); void buildOutlineNode( {required SourceLibraryBuilder libraryBuilder, @@ -212,17 +212,20 @@ @override void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - BodyBuilderContext bodyBuilderContext, - Annotatable annotatable, - {required bool isClassInstanceMember, - required bool createFileUriExpression}) { - buildMetadataForOutlineExpressions(libraryBuilder, _fragment.enclosingScope, - bodyBuilderContext, annotatable, _fragment.metadata, - fileUri: _fragment.fileUri, - createFileUriExpression: createFileUriExpression); + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required BodyBuilderContext bodyBuilderContext, + required Annotatable annotatable, + required Uri annotatableFileUri, + required bool isClassInstanceMember}) { + buildMetadataForOutlineExpressions( + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope, + bodyBuilderContext: bodyBuilderContext, + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + metadata: _fragment.metadata); buildTypeParametersForOutlineExpressions( classHierarchy, @@ -437,17 +440,20 @@ @override void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - BodyBuilderContext bodyBuilderContext, - Annotatable annotatable, - {required bool isClassInstanceMember, - required bool createFileUriExpression}) { - buildMetadataForOutlineExpressions(libraryBuilder, _fragment.enclosingScope, - bodyBuilderContext, annotatable, _fragment.metadata, - fileUri: _fragment.fileUri, - createFileUriExpression: createFileUriExpression); + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required BodyBuilderContext bodyBuilderContext, + required Annotatable annotatable, + required Uri annotatableFileUri, + required bool isClassInstanceMember}) { + buildMetadataForOutlineExpressions( + libraryBuilder: libraryBuilder, + scope: _fragment.enclosingScope, + bodyBuilderContext: bodyBuilderContext, + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + metadata: _fragment.metadata); buildTypeParametersForOutlineExpressions( classHierarchy,
diff --git a/pkg/front_end/lib/src/fragment/util.dart b/pkg/front_end/lib/src/fragment/util.dart index f22c0a7..81374c9 100644 --- a/pkg/front_end/lib/src/fragment/util.dart +++ b/pkg/front_end/lib/src/fragment/util.dart
@@ -46,16 +46,19 @@ } void buildMetadataForOutlineExpressions( - SourceLibraryBuilder libraryBuilder, - LookupScope parentScope, - BodyBuilderContext bodyBuilderContext, - Annotatable annotatable, - List<MetadataBuilder>? metadata, - {required Uri fileUri, - required bool createFileUriExpression}) { - MetadataBuilder.buildAnnotations(annotatable, metadata, bodyBuilderContext, - libraryBuilder, fileUri, parentScope, - createFileUriExpression: createFileUriExpression); + {required SourceLibraryBuilder libraryBuilder, + required LookupScope scope, + required BodyBuilderContext bodyBuilderContext, + required Annotatable annotatable, + required Uri annotatableFileUri, + required List<MetadataBuilder>? metadata}) { + MetadataBuilder.buildAnnotations( + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + metadata: metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: scope); } void buildTypeParametersForOutlineExpressions( @@ -97,212 +100,6 @@ scope: scope, buildDefaultValue: isClassInstanceMember); } -/// Common interface for fragments that can declare a field. -abstract class FieldDeclaration { - FieldQuality get fieldQuality; - - GetterQuality get getterQuality; - - SetterQuality get setterQuality; - - /// The metadata declared on this fragment. - List<MetadataBuilder>? get metadata; - - /// Builds the core AST structures for this field declaration as needed for - /// the outline. - void buildOutlineNode(SourceLibraryBuilder libraryBuilder, - NameScheme nameScheme, BuildNodesCallback f, FieldReference references, - {required List<TypeParameter>? classTypeParameters}); - - void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - List<Annotatable> annotatables, - {required bool isClassInstanceMember, - required bool createFileUriExpression}); - - int computeDefaultTypes(ComputeDefaultTypeContext context); - - void checkTypes(SourceLibraryBuilder libraryBuilder, - TypeEnvironment typeEnvironment, SourcePropertyBuilder? setterBuilder); - - /// Checks the variance of type parameters [sourceClassBuilder] used in the - /// type of this field declaration. - void checkVariance( - SourceClassBuilder sourceClassBuilder, TypeEnvironment typeEnvironment); - - /// The references to the members from this field declaration that are - /// accessible in exports through the name of the builder. - Iterable<Reference> getExportedMemberReferences(FieldReference references); - - /// Return `true` if the declaration introduces a setter. - bool get hasSetter; - - /// Return `true` if the declaration has an initializer. - bool get hasInitializer; - - /// Return `true` if the declaration is final. - bool get isFinal; - - /// Return `true` if the declaration is late. - bool get isLate; - - /// Return `true` if the declaration is in instance field declared in an - /// extension type. - bool get isExtensionTypeDeclaredInstanceField; - - /// Returns `true` if this field is declared by an enum element. - bool get isEnumElement; - - /// The [ClassMember]s for the getter introduced by this field declaration. - List<ClassMember> get localMembers; - - /// The [ClassMember]s for the setter introduced by this field declaration, - /// if any. - List<ClassMember> get localSetters; - - /// The [Member] uses as the target for reading from this field declaration. - Member get readTarget; - - /// The [Member] uses as the target for writing to this field declaration, or - /// `null` if this field declaration has no setter. - Member? get writeTarget; - - /// The [DartType] of this field declaration. - abstract DartType fieldType; - - /// Creates the [Initializer] for the invalid initialization of this field. - /// - /// This is only used for instance fields. - Initializer buildErroneousInitializer(Expression effect, Expression value, - {required int fileOffset}); - - /// Creates the AST node for this field as the default initializer. - /// - /// This is only used for instance fields. - void buildImplicitDefaultValue(); - - /// Creates the [Initializer] for the implicit initialization of this field - /// in a constructor. - /// - /// This is only used for instance fields. - Initializer buildImplicitInitializer(); - - /// Builds the [Initializer]s for each field used to encode this field - /// using the [fileOffset] for the created nodes and [value] as the initial - /// field value. - /// - /// This is only used for instance fields. - List<Initializer> buildInitializer(int fileOffset, Expression value, - {required bool isSynthetic}); - - /// Ensures that the type of this field declaration has been computed. - void ensureTypes( - ClassMembersBuilder membersBuilder, - Set<ClassMember>? getterOverrideDependencies, - Set<ClassMember>? setterOverrideDependencies); - - /// Infers the type of this field declaration. - DartType inferType(ClassHierarchyBase hierarchy); - - shared.Expression? get initializerExpression; -} - -mixin FieldDeclarationMixin - implements FieldDeclaration, Inferable, InferredTypeListener { - Uri get fileUri; - - int get nameOffset; - - SourcePropertyBuilder get builder; - - bool get isConst; - - /// The [TypeBuilder] for the declared type of this field declaration. - TypeBuilder get type; - - void _setCovariantByClassInternal(); - - abstract DartType _fieldTypeInternal; - - @override - void onInferredType(DartType type) { - fieldType = type; - } - - @override - void inferTypes(ClassHierarchyBase hierarchy) { - inferType(hierarchy); - } - - @override - DartType inferType(ClassHierarchyBase hierarchy) { - if (fieldType is! InferredType) { - // We have already inferred a type. - return fieldType; - } - - return builder.libraryBuilder.loader - .withUriForCrashReporting(fileUri, nameOffset, () { - InferredType implicitFieldType = fieldType as InferredType; - DartType inferredType = implicitFieldType.computeType(hierarchy); - if (fieldType is InferredType) { - // `fieldType` may have changed if a circularity was detected when - // [inferredType] was computed. - type.registerInferredType(inferredType); - - // TODO(johnniwinther): Isn't this handled in the [fieldType] setter? - IncludesTypeParametersNonCovariantly? needsCheckVisitor; - DeclarationBuilder? declarationBuilder = builder.declarationBuilder; - if (declarationBuilder is ClassBuilder) { - Class enclosingClass = declarationBuilder.cls; - if (enclosingClass.typeParameters.isNotEmpty) { - needsCheckVisitor = new IncludesTypeParametersNonCovariantly( - enclosingClass.typeParameters, - // We are checking the field type as if it is the type of the - // parameter of the implicit setter and this is a contravariant - // position. - initialVariance: Variance.contravariant); - } - } - if (needsCheckVisitor != null) { - if (fieldType.accept(needsCheckVisitor)) { - _setCovariantByClassInternal(); - } - } - } - return fieldType; - }); - } - - @override - // Coverage-ignore(suite): Not run. - DartType get fieldType => _fieldTypeInternal; - - @override - void set fieldType(DartType value) { - _fieldTypeInternal = value; - DeclarationBuilder? declarationBuilder = builder.declarationBuilder; - // TODO(johnniwinther): Should this be `hasSetter`? - if (!isFinal && !isConst && declarationBuilder is ClassBuilder) { - Class enclosingClass = declarationBuilder.cls; - if (enclosingClass.typeParameters.isNotEmpty) { - IncludesTypeParametersNonCovariantly needsCheckVisitor = - new IncludesTypeParametersNonCovariantly( - enclosingClass.typeParameters, - // We are checking the field type as if it is the type of the - // parameter of the implicit setter and this is a contravariant - // position. - initialVariance: Variance.contravariant); - if (value.accept(needsCheckVisitor)) { - _setCovariantByClassInternal(); - } - } - } - } -} - sealed class PropertyEncodingStrategy { factory PropertyEncodingStrategy(DeclarationBuilder? declarationBuilder, {required bool isInstanceMember}) {
diff --git a/pkg/front_end/lib/src/kernel/record_use.dart b/pkg/front_end/lib/src/kernel/record_use.dart index db4917a..d2866c3 100644 --- a/pkg/front_end/lib/src/kernel/record_use.dart +++ b/pkg/front_end/lib/src/kernel/record_use.dart
@@ -12,6 +12,7 @@ import '../base/messages.dart' show messageRecordUseCannotBePlacedHere; import 'constant_evaluator.dart' show ErrorReporter; +// Coverage-ignore(suite): Not run. /// Get all of the `@RecordUse` annotations from `package:meta` /// that are attached to the specified [node]. Iterable<InstanceConstant> findRecordUseAnnotation(Annotatable node) => @@ -19,15 +20,18 @@ .whereType<ConstantExpression>() .map((expression) => expression.constant) .whereType<InstanceConstant>() - .where((instance) => isRecordUse(instance.classNode)) - .toList(growable: false); + .where((instance) => isRecordUse(instance.classNode)); + +// Coverage-ignore(suite): Not run. +bool hasRecordUseAnnotation(Annotatable node) => + findRecordUseAnnotation(node).isNotEmpty; // Coverage-ignore(suite): Not run. final Uri _metaLibraryUri = new Uri(scheme: 'package', path: 'meta/meta.dart'); +// Coverage-ignore(suite): Not run. bool isRecordUse(Class cls) => cls.name == 'RecordUse' && - // Coverage-ignore(suite): Not run. cls.enclosingLibrary.importUri == _metaLibraryUri; // Coverage-ignore(suite): Not run.
diff --git a/pkg/front_end/lib/src/kernel/utils.dart b/pkg/front_end/lib/src/kernel/utils.dart index 0211286..928a213 100644 --- a/pkg/front_end/lib/src/kernel/utils.dart +++ b/pkg/front_end/lib/src/kernel/utils.dart
@@ -259,7 +259,8 @@ final Identifier dummyIdentifier = new SimpleIdentifier(dummyToken); final CombinatorBuilder dummyCombinator = new CombinatorBuilder(false, {}, -1, dummyUri); -final MetadataBuilder dummyMetadataBuilder = new MetadataBuilder(dummyToken); +final MetadataBuilder dummyMetadataBuilder = + new MetadataBuilder(dummyToken, dummyUri); final TypeBuilder dummyTypeBuilder = new FixedTypeBuilderImpl(dummyDartType, dummyUri, -1); final FormalParameterBuilder dummyFormalParameterBuilder =
diff --git a/pkg/front_end/lib/src/source/builder_factory.dart b/pkg/front_end/lib/src/source/builder_factory.dart index 681bb16..d4e1d1f 100644 --- a/pkg/front_end/lib/src/source/builder_factory.dart +++ b/pkg/front_end/lib/src/source/builder_factory.dart
@@ -536,7 +536,7 @@ for (int index = 0; index < oldParameterBuilders.length; index++) { NominalParameterBuilder oldVariable = oldParameterBuilders[index]; TypeParameterFragment? oldFragment = oldParameterFragments?[index]; - Uri? fileUri = oldFragment?.fileUri ?? oldVariable.fileUri; + Uri fileUri = (oldFragment?.fileUri ?? oldVariable.fileUri)!; int fileOffset = oldFragment?.nameOffset ?? oldVariable.fileOffset; SourceNominalParameterBuilder newVariable = new SourceNominalParameterBuilder(
diff --git a/pkg/front_end/lib/src/source/outline_builder.dart b/pkg/front_end/lib/src/source/outline_builder.dart index ed6c89a..5a96dd4 100644 --- a/pkg/front_end/lib/src/source/outline_builder.dart +++ b/pkg/front_end/lib/src/source/outline_builder.dart
@@ -598,7 +598,7 @@ Object? sentinel = pop(); // prefix or constructor push(sentinel is ParserRecovery ? sentinel - : new MetadataBuilder(beginToken)); + : new MetadataBuilder(beginToken, _compilationUnit.fileUri)); } @override
diff --git a/pkg/front_end/lib/src/source/source_class_builder.dart b/pkg/front_end/lib/src/source/source_class_builder.dart index 15f15a6..bdcd4d8 100644 --- a/pkg/front_end/lib/src/source/source_class_builder.dart +++ b/pkg/front_end/lib/src/source/source_class_builder.dart
@@ -513,6 +513,7 @@ BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); _introductory.buildOutlineExpressions( annotatable: cls, + annotatableFileUri: cls.fileUri, bodyBuilderContext: bodyBuilderContext, libraryBuilder: libraryBuilder, classHierarchy: classHierarchy, @@ -520,6 +521,7 @@ for (ClassDeclaration augmentation in _augmentations) { augmentation.buildOutlineExpressions( annotatable: cls, + annotatableFileUri: cls.fileUri, bodyBuilderContext: bodyBuilderContext, classHierarchy: classHierarchy, libraryBuilder: libraryBuilder,
diff --git a/pkg/front_end/lib/src/source/source_compilation_unit.dart b/pkg/front_end/lib/src/source/source_compilation_unit.dart index d377ce6..63c3ba5 100644 --- a/pkg/front_end/lib/src/source/source_compilation_unit.dart +++ b/pkg/front_end/lib/src/source/source_compilation_unit.dart
@@ -878,11 +878,16 @@ @override void buildOutlineExpressions( - Annotatable annotatable, BodyBuilderContext bodyBuilderContext, - {required bool createFileUriExpression}) { - MetadataBuilder.buildAnnotations(annotatable, metadata, bodyBuilderContext, - libraryBuilder, fileUri, compilationUnitScope, - createFileUriExpression: createFileUriExpression); + {required Annotatable annotatable, + required Uri annotatableFileUri, + required BodyBuilderContext bodyBuilderContext}) { + MetadataBuilder.buildAnnotations( + annotatable: annotatable, + annotatableFileUri: annotatableFileUri, + metadata: metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: compilationUnitScope); } @override
diff --git a/pkg/front_end/lib/src/source/source_constructor_builder.dart b/pkg/front_end/lib/src/source/source_constructor_builder.dart index 1dd6ca6..5d25ca9 100644 --- a/pkg/front_end/lib/src/source/source_constructor_builder.dart +++ b/pkg/front_end/lib/src/source/source_constructor_builder.dart
@@ -560,22 +560,20 @@ if (!hasBuiltOutlineExpressions) { _introductory.buildOutlineExpressions( annotatables: annotatables, + annotatablesFileUri: invokeTarget.fileUri, libraryBuilder: libraryBuilder, declarationBuilder: declarationBuilder, constructorBuilder: this, classHierarchy: classHierarchy, - createFileUriExpression: - _invokeTarget.fileUri != _introductory.fileUri, delayedDefaultValueCloners: delayedDefaultValueCloners); for (ConstructorDeclaration augmentation in _augmentations) { augmentation.buildOutlineExpressions( annotatables: annotatables, + annotatablesFileUri: invokeTarget.fileUri, libraryBuilder: libraryBuilder, declarationBuilder: declarationBuilder, constructorBuilder: this, classHierarchy: classHierarchy, - createFileUriExpression: - _invokeTarget.fileUri != augmentation.fileUri, delayedDefaultValueCloners: delayedDefaultValueCloners); } hasBuiltOutlineExpressions = true;
diff --git a/pkg/front_end/lib/src/source/source_enum_builder.dart b/pkg/front_end/lib/src/source/source_enum_builder.dart index 4423bb7..5dcf9b5 100644 --- a/pkg/front_end/lib/src/source/source_enum_builder.dart +++ b/pkg/front_end/lib/src/source/source_enum_builder.dart
@@ -30,6 +30,7 @@ import '../builder/nullability_builder.dart'; import '../builder/type_builder.dart'; import '../fragment/constructor/declaration.dart'; +import '../fragment/field/declaration.dart'; import '../fragment/fragment.dart'; import '../fragment/method/declaration.dart'; import '../kernel/body_builder_context.dart'; @@ -477,13 +478,13 @@ @override void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - SourceMethodBuilder methodBuilder, - Annotatable annotatable, - {required bool isClassInstanceMember, - required bool createFileUriExpression}) { + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required SourceMethodBuilder methodBuilder, + required Annotatable annotatable, + required Uri annotatableFileUri, + required bool isClassInstanceMember}) { Name toStringName = new Name(_enumToStringName, classHierarchy.coreTypes.coreLibrary); Member? superToString = _enumBuilder.cls.superclass != null @@ -641,12 +642,12 @@ @override void buildOutlineExpressions( - ClassHierarchy classHierarchy, - SourceLibraryBuilder libraryBuilder, - DeclarationBuilder? declarationBuilder, - List<Annotatable> annotatables, - {required bool isClassInstanceMember, - required bool createFileUriExpression}) { + {required ClassHierarchy classHierarchy, + required SourceLibraryBuilder libraryBuilder, + required DeclarationBuilder? declarationBuilder, + required List<Annotatable> annotatables, + required Uri annotatablesFileUri, + required bool isClassInstanceMember}) { List<Expression> values = <Expression>[]; for (EnumElementFragment enumElement in _sourceEnumBuilder._enumElements) { enumElement.declaration.inferType(classHierarchy);
diff --git a/pkg/front_end/lib/src/source/source_extension_builder.dart b/pkg/front_end/lib/src/source/source_extension_builder.dart index 1b47c6d..80f540c 100644 --- a/pkg/front_end/lib/src/source/source_extension_builder.dart +++ b/pkg/front_end/lib/src/source/source_extension_builder.dart
@@ -160,12 +160,12 @@ void _buildOutlineExpressionsForFragment(ExtensionFragment fragment, ClassHierarchy classHierarchy, BodyBuilderContext bodyBuilderContext) { MetadataBuilder.buildAnnotations( - extension, - fragment.metadata, - bodyBuilderContext, - libraryBuilder, - fragment.fileUri, - fragment.enclosingScope); + annotatable: extension, + annotatableFileUri: extension.fileUri, + metadata: fragment.metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: fragment.enclosingScope); } void buildOutlineExpressions(ClassHierarchy classHierarchy,
diff --git a/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart b/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart index 1324f41..c82d767 100644 --- a/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart +++ b/pkg/front_end/lib/src/source/source_extension_type_declaration_builder.dart
@@ -703,18 +703,19 @@ void buildOutlineExpressions(ClassHierarchy classHierarchy, List<DelayedDefaultValueCloner> delayedDefaultValueCloners) { + BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); MetadataBuilder.buildAnnotations( - extensionTypeDeclaration, - _introductory.metadata, - createBodyBuilderContext(), - libraryBuilder, - _introductory.fileUri, - _introductory.enclosingScope); + annotatable: extensionTypeDeclaration, + annotatableFileUri: extensionTypeDeclaration.fileUri, + metadata: _introductory.metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: _introductory.enclosingScope); if (_introductory.typeParameters != null) { for (int i = 0; i < _introductory.typeParameters!.length; i++) { _introductory.typeParameters![i].builder.buildOutlineExpressions( - libraryBuilder, createBodyBuilderContext(), classHierarchy); + libraryBuilder, bodyBuilderContext, classHierarchy); } }
diff --git a/pkg/front_end/lib/src/source/source_factory_builder.dart b/pkg/front_end/lib/src/source/source_factory_builder.dart index b3634f7..ac99bec 100644 --- a/pkg/front_end/lib/src/source/source_factory_builder.dart +++ b/pkg/front_end/lib/src/source/source_factory_builder.dart
@@ -297,16 +297,16 @@ factoryBuilder: this, classHierarchy: classHierarchy, delayedDefaultValueCloners: delayedDefaultValueCloners, - createFileUriExpression: - _introductory.fileUri != _lastDeclaration.fileUri); + annotatables: annotatables, + annotatablesFileUri: _procedure.fileUri); for (FactoryDeclaration augmentation in _augmentations) { augmentation.buildOutlineExpressions( libraryBuilder: libraryBuilder, factoryBuilder: this, classHierarchy: classHierarchy, delayedDefaultValueCloners: delayedDefaultValueCloners, - createFileUriExpression: - augmentation.fileUri != _lastDeclaration.fileUri); + annotatables: annotatables, + annotatablesFileUri: _procedure.fileUri); } }
diff --git a/pkg/front_end/lib/src/source/source_library_builder.dart b/pkg/front_end/lib/src/source/source_library_builder.dart index 6857fca..4347ef3 100644 --- a/pkg/front_end/lib/src/source/source_library_builder.dart +++ b/pkg/front_end/lib/src/source/source_library_builder.dart
@@ -843,8 +843,10 @@ void buildOutlineExpressions(ClassHierarchy classHierarchy, List<DelayedDefaultValueCloner> delayedDefaultValueCloners) { - compilationUnit.buildOutlineExpressions(library, createBodyBuilderContext(), - createFileUriExpression: false); + compilationUnit.buildOutlineExpressions( + annotatable: library, + annotatableFileUri: library.fileUri, + bodyBuilderContext: createBodyBuilderContext()); Iterator<Builder> iterator = localMembersIterator; while (iterator.moveNext()) {
diff --git a/pkg/front_end/lib/src/source/source_method_builder.dart b/pkg/front_end/lib/src/source/source_method_builder.dart index 30afc57..109272c 100644 --- a/pkg/front_end/lib/src/source/source_method_builder.dart +++ b/pkg/front_end/lib/src/source/source_method_builder.dart
@@ -146,17 +146,23 @@ void buildOutlineExpressions(ClassHierarchy classHierarchy, List<DelayedDefaultValueCloner> delayedDefaultValueCloners) { if (!hasBuiltOutlineExpressions) { - _introductory.buildOutlineExpressions(classHierarchy, libraryBuilder, - declarationBuilder, this, _invokeTarget, - isClassInstanceMember: isClassInstanceMember, - createFileUriExpression: - _invokeTarget.fileUri != _introductory.fileUri); + _introductory.buildOutlineExpressions( + classHierarchy: classHierarchy, + libraryBuilder: libraryBuilder, + declarationBuilder: declarationBuilder, + methodBuilder: this, + annotatable: _invokeTarget, + annotatableFileUri: _invokeTarget.fileUri, + isClassInstanceMember: isClassInstanceMember); for (MethodDeclaration augmentation in _augmentations) { - augmentation.buildOutlineExpressions(classHierarchy, libraryBuilder, - declarationBuilder, this, _invokeTarget, - isClassInstanceMember: isClassInstanceMember, - createFileUriExpression: - _invokeTarget.fileUri != augmentation.fileUri); + augmentation.buildOutlineExpressions( + classHierarchy: classHierarchy, + libraryBuilder: libraryBuilder, + declarationBuilder: declarationBuilder, + methodBuilder: this, + annotatable: _invokeTarget, + annotatableFileUri: _invokeTarget.fileUri, + isClassInstanceMember: isClassInstanceMember); } hasBuiltOutlineExpressions = true; }
diff --git a/pkg/front_end/lib/src/source/source_property_builder.dart b/pkg/front_end/lib/src/source/source_property_builder.dart index e44cc21..61306dd 100644 --- a/pkg/front_end/lib/src/source/source_property_builder.dart +++ b/pkg/front_end/lib/src/source/source_property_builder.dart
@@ -15,7 +15,7 @@ import '../builder/declaration_builders.dart'; import '../builder/metadata_builder.dart'; import '../builder/property_builder.dart'; -import '../fragment/fragment.dart'; +import '../fragment/field/declaration.dart'; import '../fragment/getter/declaration.dart'; import '../fragment/setter/declaration.dart'; import '../kernel/hierarchy/class_member.dart'; @@ -220,25 +220,24 @@ List<DelayedDefaultValueCloner> delayedDefaultValueCloners) { if (!hasBuiltOutlineExpressions) { _introductoryField?.buildOutlineExpressions( - classHierarchy, - libraryBuilder, - declarationBuilder, - [ + classHierarchy: classHierarchy, + libraryBuilder: libraryBuilder, + declarationBuilder: declarationBuilder, + annotatables: [ readTarget as Annotatable, if (writeTarget != null && readTarget != writeTarget) writeTarget as Annotatable ], - isClassInstanceMember: isClassInstanceMember, - createFileUriExpression: false); + annotatablesFileUri: readTarget!.fileUri, + isClassInstanceMember: isClassInstanceMember); _introductoryGetable?.buildOutlineExpressions( classHierarchy: classHierarchy, libraryBuilder: libraryBuilder, declarationBuilder: declarationBuilder, propertyBuilder: this, annotatable: readTarget as Annotatable, - isClassInstanceMember: isClassInstanceMember, - createFileUriExpression: - _introductoryGetable?.fileUri != _lastGetable?.fileUri); + annotatableFileUri: readTarget!.fileUri, + isClassInstanceMember: isClassInstanceMember); List<GetterDeclaration>? getterAugmentations = _getterAugmentations; if (getterAugmentations != null) { for (GetterDeclaration augmentation in getterAugmentations) { @@ -248,9 +247,8 @@ declarationBuilder: declarationBuilder, propertyBuilder: this, annotatable: readTarget as Annotatable, - isClassInstanceMember: isClassInstanceMember, - createFileUriExpression: - augmentation.fileUri != _lastGetable?.fileUri); + annotatableFileUri: readTarget!.fileUri, + isClassInstanceMember: isClassInstanceMember); } } _introductorySetable?.buildOutlineExpressions( @@ -259,9 +257,8 @@ declarationBuilder: declarationBuilder, propertyBuilder: this, annotatable: writeTarget as Annotatable, - isClassInstanceMember: isClassInstanceMember, - createFileUriExpression: - _introductorySetable?.fileUri != _lastSetable?.fileUri); + annotatableFileUri: writeTarget!.fileUri, + isClassInstanceMember: isClassInstanceMember); List<SetterDeclaration>? setterAugmentations = _setterAugmentations; if (setterAugmentations != null) { for (SetterDeclaration augmentation in setterAugmentations) { @@ -271,9 +268,8 @@ declarationBuilder: declarationBuilder, propertyBuilder: this, annotatable: writeTarget as Annotatable, - isClassInstanceMember: isClassInstanceMember, - createFileUriExpression: - augmentation.fileUri != _lastSetable?.fileUri); + annotatableFileUri: writeTarget!.fileUri, + isClassInstanceMember: isClassInstanceMember); } } hasBuiltOutlineExpressions = true;
diff --git a/pkg/front_end/lib/src/source/source_type_alias_builder.dart b/pkg/front_end/lib/src/source/source_type_alias_builder.dart index 62d9ede..04df66f 100644 --- a/pkg/front_end/lib/src/source/source_type_alias_builder.dart +++ b/pkg/front_end/lib/src/source/source_type_alias_builder.dart
@@ -368,17 +368,18 @@ void buildOutlineExpressions(ClassHierarchy classHierarchy, List<DelayedDefaultValueCloner> delayedDefaultValueCloners) { + BodyBuilderContext bodyBuilderContext = createBodyBuilderContext(); MetadataBuilder.buildAnnotations( - typedef, - _introductory.metadata, - createBodyBuilderContext(), - libraryBuilder, - fileUri, - _introductory.enclosingScope); + annotatable: typedef, + annotatableFileUri: typedef.fileUri, + metadata: _introductory.metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: _introductory.enclosingScope); if (typeParameters != null) { for (int i = 0; i < typeParameters!.length; i++) { typeParameters![i].buildOutlineExpressions( - libraryBuilder, createBodyBuilderContext(), classHierarchy); + libraryBuilder, bodyBuilderContext, classHierarchy); } } _tearOffDependencies?.forEach((Procedure tearOff, Member target) {
diff --git a/pkg/front_end/lib/src/source/source_type_parameter_builder.dart b/pkg/front_end/lib/src/source/source_type_parameter_builder.dart index 5ff1dec..0f3a6e4 100644 --- a/pkg/front_end/lib/src/source/source_type_parameter_builder.dart +++ b/pkg/front_end/lib/src/source/source_type_parameter_builder.dart
@@ -49,7 +49,7 @@ bool get isWildcard => _declaration.isWildcard; @override - Uri? get fileUri => _declaration.fileUri; + Uri get fileUri => _declaration.fileUri; void buildOutlineExpressions(SourceLibraryBuilder libraryBuilder, BodyBuilderContext bodyBuilderContext, ClassHierarchy classHierarchy) { @@ -94,14 +94,14 @@ int get fileOffset; - Uri? get fileUri; + Uri get fileUri; void buildOutlineExpressions( {required SourceLibraryBuilder libraryBuilder, required BodyBuilderContext bodyBuilderContext, required ClassHierarchy classHierarchy, required TypeParameter parameter, - required Uri? annotatableFileUri}); + required Uri annotatableFileUri}); } class RegularNominalParameterDeclaration @@ -114,7 +114,7 @@ int get fileOffset => _fragment.nameOffset; @override - Uri? get fileUri => _fragment.fileUri; + Uri get fileUri => _fragment.fileUri; @override bool get isWildcard => _fragment.isWildcard; @@ -131,15 +131,14 @@ required BodyBuilderContext bodyBuilderContext, required ClassHierarchy classHierarchy, required TypeParameter parameter, - required Uri? annotatableFileUri}) { + required Uri annotatableFileUri}) { MetadataBuilder.buildAnnotations( - parameter, - _fragment.metadata, - bodyBuilderContext, - libraryBuilder, - _fragment.fileUri, - _fragment.typeParameterScope, - createFileUriExpression: _fragment.fileUri != annotatableFileUri); + annotatable: parameter, + annotatableFileUri: annotatableFileUri, + metadata: _fragment.metadata, + bodyBuilderContext: bodyBuilderContext, + libraryBuilder: libraryBuilder, + scope: _fragment.typeParameterScope); } } @@ -157,7 +156,7 @@ final bool isWildcard; @override - final Uri? fileUri; + final Uri fileUri; DirectNominalParameterDeclaration( {required this.name, @@ -184,7 +183,7 @@ final int fileOffset; @override - final Uri? fileUri; + final Uri fileUri; @override final TypeParameterKind kind;
diff --git a/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart b/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart index 50a0d14..b1b0e07 100644 --- a/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart +++ b/pkg/front_end/lib/src/source/type_parameter_scope_builder.dart
@@ -26,6 +26,7 @@ import '../builder/type_builder.dart'; import '../fragment/constructor/declaration.dart'; import '../fragment/factory/declaration.dart'; +import '../fragment/field/declaration.dart'; import '../fragment/fragment.dart'; import '../fragment/getter/declaration.dart'; import '../fragment/method/declaration.dart'; @@ -1700,7 +1701,7 @@ context: [ templateTypeParameterDuplicatedNameCause .withArguments(tv.name) - .withLocation(existing.fileUri!, existing.fileOffset, + .withLocation(existing.fileUri, existing.fileOffset, existing.name.length) ]); }
diff --git a/pkg/front_end/test/coverage_suite_expected.dart b/pkg/front_end/test/coverage_suite_expected.dart index e3a2fc1..012277a 100644 --- a/pkg/front_end/test/coverage_suite_expected.dart +++ b/pkg/front_end/test/coverage_suite_expected.dart
@@ -335,7 +335,7 @@ ), // 100.0%. "package:front_end/src/builder/metadata_builder.dart": ( - hitCount: 37, + hitCount: 41, missCount: 0, ), // 100.0%. @@ -490,7 +490,7 @@ ), // 100.0%. "package:front_end/src/fragment/class/declaration.dart": ( - hitCount: 178, + hitCount: 170, missCount: 0, ), // 100.0%. @@ -505,7 +505,7 @@ ), // 100.0%. "package:front_end/src/fragment/constructor/declaration.dart": ( - hitCount: 677, + hitCount: 673, missCount: 0, ), // 100.0%. @@ -520,7 +520,7 @@ ), // 100.0%. "package:front_end/src/fragment/enum_element.dart": ( - hitCount: 283, + hitCount: 282, missCount: 0, ), // 100.0%. @@ -545,7 +545,7 @@ ), // 100.0%. "package:front_end/src/fragment/factory/declaration.dart": ( - hitCount: 125, + hitCount: 120, missCount: 0, ), // 100.0%. @@ -555,7 +555,7 @@ ), // 100.0%. "package:front_end/src/fragment/field.dart": ( - hitCount: 394, + hitCount: 28, missCount: 0, ), // 100.0%. @@ -569,6 +569,11 @@ missCount: 0, ), // 100.0%. + "package:front_end/src/fragment/field/declaration.dart": ( + hitCount: 412, + missCount: 0, + ), + // 100.0%. "package:front_end/src/fragment/field/encoding.dart": ( hitCount: 996, missCount: 0, @@ -585,12 +590,12 @@ ), // 100.0%. "package:front_end/src/fragment/getter/declaration.dart": ( - hitCount: 120, + hitCount: 117, missCount: 0, ), // 100.0%. "package:front_end/src/fragment/getter/encoding.dart": ( - hitCount: 368, + hitCount: 364, missCount: 0, ), // 100.0%. @@ -610,7 +615,7 @@ ), // 100.0%. "package:front_end/src/fragment/method/encoding.dart": ( - hitCount: 642, + hitCount: 638, missCount: 0, ), // 100.0%. @@ -640,12 +645,12 @@ ), // 100.0%. "package:front_end/src/fragment/setter/declaration.dart": ( - hitCount: 116, + hitCount: 113, missCount: 0, ), // 100.0%. "package:front_end/src/fragment/setter/encoding.dart": ( - hitCount: 393, + hitCount: 389, missCount: 0, ), // 100.0%. @@ -660,7 +665,7 @@ ), // 100.0%. "package:front_end/src/fragment/util.dart": ( - hitCount: 127, + hitCount: 80, missCount: 0, ), // 100.0%. @@ -875,7 +880,7 @@ ), // 100.0%. "package:front_end/src/kernel/utils.dart": ( - hitCount: 85, + hitCount: 86, missCount: 0, ), // 100.0%. @@ -915,7 +920,7 @@ ), // 100.0%. "package:front_end/src/source/outline_builder.dart": ( - hitCount: 2107, + hitCount: 2109, missCount: 0, ), // 100.0%. @@ -935,17 +940,17 @@ ), // 100.0%. "package:front_end/src/source/source_class_builder.dart": ( - hitCount: 1428, + hitCount: 1432, missCount: 0, ), // 100.0%. "package:front_end/src/source/source_compilation_unit.dart": ( - hitCount: 664, + hitCount: 663, missCount: 0, ), // 100.0%. "package:front_end/src/source/source_constructor_builder.dart": ( - hitCount: 415, + hitCount: 410, missCount: 0, ), // 100.0%. @@ -955,18 +960,18 @@ ), // 100.0%. "package:front_end/src/source/source_extension_builder.dart": ( - hitCount: 129, + hitCount: 130, missCount: 0, ), // 100.0%. "package:front_end/src/source/source_extension_type_declaration_builder.dart": ( - hitCount: 536, + hitCount: 535, missCount: 0, ), // 100.0%. "package:front_end/src/source/source_factory_builder.dart": ( - hitCount: 132, + hitCount: 129, missCount: 0, ), // 100.0%. @@ -976,7 +981,7 @@ ), // 100.0%. "package:front_end/src/source/source_library_builder.dart": ( - hitCount: 1069, + hitCount: 1071, missCount: 0, ), // 100.0%. @@ -991,12 +996,12 @@ ), // 100.0%. "package:front_end/src/source/source_method_builder.dart": ( - hitCount: 195, + hitCount: 190, missCount: 0, ), // 100.0%. "package:front_end/src/source/source_property_builder.dart": ( - hitCount: 664, + hitCount: 656, missCount: 0, ), // 100.0%. @@ -1006,7 +1011,7 @@ ), // 100.0%. "package:front_end/src/source/source_type_parameter_builder.dart": ( - hitCount: 111, + hitCount: 106, missCount: 0, ), // 100.0%.
diff --git a/pkg/front_end/testcases/extensions/patch/main.dart.strong.expect b/pkg/front_end/testcases/extensions/patch/main.dart.strong.expect index fdf90e1..75585b5 100644 --- a/pkg/front_end/testcases/extensions/patch/main.dart.strong.expect +++ b/pkg/front_end/testcases/extensions/patch/main.dart.strong.expect
@@ -16,14 +16,14 @@ import "dart:_internal"; -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension IntExtension on core::int { method method1 = test::IntExtension|method1; method tearoff method1 = test::IntExtension|get#method1; method method2 = test::IntExtension|method2; method tearoff method2 = test::IntExtension|get#method2; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension GenericExtension<T extends core::Object? = dynamic> on T% { method method3 = test::GenericExtension|method3; method tearoff method3 = test::GenericExtension|get#method3;
diff --git a/pkg/front_end/testcases/extensions/patch/main.dart.strong.modular.expect b/pkg/front_end/testcases/extensions/patch/main.dart.strong.modular.expect index fdf90e1..75585b5 100644 --- a/pkg/front_end/testcases/extensions/patch/main.dart.strong.modular.expect +++ b/pkg/front_end/testcases/extensions/patch/main.dart.strong.modular.expect
@@ -16,14 +16,14 @@ import "dart:_internal"; -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension IntExtension on core::int { method method1 = test::IntExtension|method1; method tearoff method1 = test::IntExtension|get#method1; method method2 = test::IntExtension|method2; method tearoff method2 = test::IntExtension|get#method2; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension GenericExtension<T extends core::Object? = dynamic> on T% { method method3 = test::GenericExtension|method3; method tearoff method3 = test::GenericExtension|get#method3;
diff --git a/pkg/front_end/testcases/extensions/patch/main.dart.strong.outline.expect b/pkg/front_end/testcases/extensions/patch/main.dart.strong.outline.expect index d6c09a8..eddc591 100644 --- a/pkg/front_end/testcases/extensions/patch/main.dart.strong.outline.expect +++ b/pkg/front_end/testcases/extensions/patch/main.dart.strong.outline.expect
@@ -13,14 +13,14 @@ import "dart:_internal"; -@_in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch extension IntExtension on core::int { method method1 = self2::IntExtension|method1; method tearoff method1 = self2::IntExtension|get#method1; method method2 = self2::IntExtension|method2; method tearoff method2 = self2::IntExtension|get#method2; } -@_in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch extension GenericExtension<T extends core::Object? = dynamic> on T% { method method3 = self2::GenericExtension|method3; method tearoff method3 = self2::GenericExtension|get#method3; @@ -52,8 +52,8 @@ Extra constant evaluation status: -Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:5:63 -> InstanceConstant(const _Patch{}) -Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:7:5 -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:8:1 -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:16:1 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:10:4 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:18:4 -> InstanceConstant(const _Patch{}) Extra constant evaluation: evaluated: 16, effectively constant: 4
diff --git a/pkg/front_end/testcases/extensions/patch/main.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/patch/main.dart.strong.transformed.expect index fdf90e1..75585b5 100644 --- a/pkg/front_end/testcases/extensions/patch/main.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/extensions/patch/main.dart.strong.transformed.expect
@@ -16,14 +16,14 @@ import "dart:_internal"; -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension IntExtension on core::int { method method1 = test::IntExtension|method1; method tearoff method1 = test::IntExtension|get#method1; method method2 = test::IntExtension|method2; method tearoff method2 = test::IntExtension|get#method2; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension GenericExtension<T extends core::Object? = dynamic> on T% { method method3 = test::GenericExtension|method3; method tearoff method3 = test::GenericExtension|get#method3;
diff --git a/pkg/front_end/testcases/extensions/patching/main.dart.strong.expect b/pkg/front_end/testcases/extensions/patching/main.dart.strong.expect index 2583619..8265d24 100644 --- a/pkg/front_end/testcases/extensions/patching/main.dart.strong.expect +++ b/pkg/front_end/testcases/extensions/patching/main.dart.strong.expect
@@ -27,7 +27,7 @@ import "dart:_internal"; -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension Extension on core::String { method instanceMethod = test::Extension|instanceMethod; method tearoff instanceMethod = test::Extension|get#instanceMethod; @@ -40,7 +40,7 @@ set instanceProperty = test::Extension|set#instanceProperty; static set staticProperty = set test::Extension|staticProperty; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension GenericExtension<T extends core::Object? = dynamic> on T% { method instanceMethod = test::GenericExtension|instanceMethod; method tearoff instanceMethod = test::GenericExtension|get#instanceMethod;
diff --git a/pkg/front_end/testcases/extensions/patching/main.dart.strong.modular.expect b/pkg/front_end/testcases/extensions/patching/main.dart.strong.modular.expect index 2583619..8265d24 100644 --- a/pkg/front_end/testcases/extensions/patching/main.dart.strong.modular.expect +++ b/pkg/front_end/testcases/extensions/patching/main.dart.strong.modular.expect
@@ -27,7 +27,7 @@ import "dart:_internal"; -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension Extension on core::String { method instanceMethod = test::Extension|instanceMethod; method tearoff instanceMethod = test::Extension|get#instanceMethod; @@ -40,7 +40,7 @@ set instanceProperty = test::Extension|set#instanceProperty; static set staticProperty = set test::Extension|staticProperty; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension GenericExtension<T extends core::Object? = dynamic> on T% { method instanceMethod = test::GenericExtension|instanceMethod; method tearoff instanceMethod = test::GenericExtension|get#instanceMethod;
diff --git a/pkg/front_end/testcases/extensions/patching/main.dart.strong.outline.expect b/pkg/front_end/testcases/extensions/patching/main.dart.strong.outline.expect index c2f7ce4..8c8eb11 100644 --- a/pkg/front_end/testcases/extensions/patching/main.dart.strong.outline.expect +++ b/pkg/front_end/testcases/extensions/patching/main.dart.strong.outline.expect
@@ -13,7 +13,7 @@ import "dart:_internal"; -@_in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch extension Extension on core::String { method instanceMethod = self2::Extension|instanceMethod; method tearoff instanceMethod = self2::Extension|get#instanceMethod; @@ -26,7 +26,7 @@ set instanceProperty = self2::Extension|set#instanceProperty; static set staticProperty = set self2::Extension|staticProperty; } -@_in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch extension GenericExtension<T extends core::Object? = dynamic> on T% { method instanceMethod = self2::GenericExtension|instanceMethod; method tearoff instanceMethod = self2::GenericExtension|get#instanceMethod; @@ -98,8 +98,8 @@ Extra constant evaluation status: -Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:6:31 -> InstanceConstant(const _Patch{}) -Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:26:39 -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:8:1 -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:35:1 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:10:4 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:13:4 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:16:4 -> InstanceConstant(const _Patch{})
diff --git a/pkg/front_end/testcases/extensions/patching/main.dart.strong.transformed.expect b/pkg/front_end/testcases/extensions/patching/main.dart.strong.transformed.expect index 2583619..8265d24 100644 --- a/pkg/front_end/testcases/extensions/patching/main.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/extensions/patching/main.dart.strong.transformed.expect
@@ -27,7 +27,7 @@ import "dart:_internal"; -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension Extension on core::String { method instanceMethod = test::Extension|instanceMethod; method tearoff instanceMethod = test::Extension|get#instanceMethod; @@ -40,7 +40,7 @@ set instanceProperty = test::Extension|set#instanceProperty; static set staticProperty = set test::Extension|staticProperty; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension GenericExtension<T extends core::Object? = dynamic> on T% { method instanceMethod = test::GenericExtension|instanceMethod; method tearoff instanceMethod = test::GenericExtension|get#instanceMethod;
diff --git a/pkg/front_end/testcases/general/inject_public/main.dart.strong.expect b/pkg/front_end/testcases/general/inject_public/main.dart.strong.expect index 4394326..91910a0 100644 --- a/pkg/front_end/testcases/general/inject_public/main.dart.strong.expect +++ b/pkg/front_end/testcases/general/inject_public/main.dart.strong.expect
@@ -70,13 +70,13 @@ ; method publicMethod() → dynamic {} } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension Extension on core::int { method injectedMethod = test::Extension|injectedMethod; method tearoff injectedMethod = test::Extension|get#injectedMethod; static method staticInjectedMethod = test::Extension|staticInjectedMethod; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension _PrivateExtension on core::int { method injectedMethod = test::_PrivateExtension|injectedMethod; method tearoff injectedMethod = test::_PrivateExtension|get#injectedMethod;
diff --git a/pkg/front_end/testcases/general/inject_public/main.dart.strong.modular.expect b/pkg/front_end/testcases/general/inject_public/main.dart.strong.modular.expect index 4394326..91910a0 100644 --- a/pkg/front_end/testcases/general/inject_public/main.dart.strong.modular.expect +++ b/pkg/front_end/testcases/general/inject_public/main.dart.strong.modular.expect
@@ -70,13 +70,13 @@ ; method publicMethod() → dynamic {} } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension Extension on core::int { method injectedMethod = test::Extension|injectedMethod; method tearoff injectedMethod = test::Extension|get#injectedMethod; static method staticInjectedMethod = test::Extension|staticInjectedMethod; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension _PrivateExtension on core::int { method injectedMethod = test::_PrivateExtension|injectedMethod; method tearoff injectedMethod = test::_PrivateExtension|get#injectedMethod;
diff --git a/pkg/front_end/testcases/general/inject_public/main.dart.strong.outline.expect b/pkg/front_end/testcases/general/inject_public/main.dart.strong.outline.expect index a34b2d0..ab70b26 100644 --- a/pkg/front_end/testcases/general/inject_public/main.dart.strong.outline.expect +++ b/pkg/front_end/testcases/general/inject_public/main.dart.strong.outline.expect
@@ -66,13 +66,13 @@ method publicMethod() → dynamic ; } -@_in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch extension Extension on core::int { method injectedMethod = self2::Extension|injectedMethod; method tearoff injectedMethod = self2::Extension|get#injectedMethod; static method staticInjectedMethod = self2::Extension|staticInjectedMethod; } -@_in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch extension _PrivateExtension on core::int { method injectedMethod = self2::_PrivateExtension|injectedMethod; method tearoff injectedMethod = self2::_PrivateExtension|get#injectedMethod; @@ -105,6 +105,6 @@ Extra constant evaluation status: Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:12:1 -> InstanceConstant(const _Patch{}) Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:32:1 -> InstanceConstant(const _Patch{}) -Evaluated: StaticGet @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const _Patch{}) -Evaluated: StaticGet @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:18:1 -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:38:1 -> InstanceConstant(const _Patch{}) Extra constant evaluation: evaluated: 13, effectively constant: 4
diff --git a/pkg/front_end/testcases/general/inject_public/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/inject_public/main.dart.strong.transformed.expect index 4394326..91910a0 100644 --- a/pkg/front_end/testcases/general/inject_public/main.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/general/inject_public/main.dart.strong.transformed.expect
@@ -70,13 +70,13 @@ ; method publicMethod() → dynamic {} } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension Extension on core::int { method injectedMethod = test::Extension|injectedMethod; method tearoff injectedMethod = test::Extension|get#injectedMethod; static method staticInjectedMethod = test::Extension|staticInjectedMethod; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension _PrivateExtension on core::int { method injectedMethod = test::_PrivateExtension|injectedMethod; method tearoff injectedMethod = test::_PrivateExtension|get#injectedMethod;
diff --git a/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.expect b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.expect index 85f0092..37dac80 100644 --- a/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.expect +++ b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.expect
@@ -75,13 +75,13 @@ : super core::Object::•() ; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension InvalidExtensionTypeParameterCount1 on core::int { } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension InvalidExtensionTypeParameterCount2<T extends core::Object? = dynamic> on core::int { } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension InvalidExtensionTypeParameterCount3<T extends core::Object? = dynamic, S extends core::Object? = dynamic> on core::int { }
diff --git a/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.modular.expect b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.modular.expect index 85f0092..37dac80 100644 --- a/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.modular.expect +++ b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.modular.expect
@@ -75,13 +75,13 @@ : super core::Object::•() ; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension InvalidExtensionTypeParameterCount1 on core::int { } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension InvalidExtensionTypeParameterCount2<T extends core::Object? = dynamic> on core::int { } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension InvalidExtensionTypeParameterCount3<T extends core::Object? = dynamic, S extends core::Object? = dynamic> on core::int { }
diff --git a/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.outline.expect b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.outline.expect index 59d64c6..c01a670 100644 --- a/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.outline.expect +++ b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.outline.expect
@@ -73,13 +73,13 @@ synthetic constructor •() → self2::InvalidClassTypeParameterCount3<self2::InvalidClassTypeParameterCount3::T%, self2::InvalidClassTypeParameterCount3::S%> ; } -@_in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch extension InvalidExtensionTypeParameterCount1 on core::int { } -@_in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch extension InvalidExtensionTypeParameterCount2<T extends core::Object? = dynamic> on core::int { } -@_in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch extension InvalidExtensionTypeParameterCount3<T extends core::Object? = dynamic, S extends core::Object? = dynamic> on core::int { } @@ -88,7 +88,7 @@ Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:8:1 -> InstanceConstant(const _Patch{}) Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:11:1 -> InstanceConstant(const _Patch{}) Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:14:1 -> InstanceConstant(const _Patch{}) -Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:14:1 -> InstanceConstant(const _Patch{}) -Evaluated: StaticGet @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const _Patch{}) -Evaluated: StaticGet @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:17:1 -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:20:1 -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:23:1 -> InstanceConstant(const _Patch{}) Extra constant evaluation: evaluated: 6, effectively constant: 6
diff --git a/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.transformed.expect index 85f0092..37dac80 100644 --- a/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/general/invalid_patch/main.dart.strong.transformed.expect
@@ -75,13 +75,13 @@ : super core::Object::•() ; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension InvalidExtensionTypeParameterCount1 on core::int { } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension InvalidExtensionTypeParameterCount2<T extends core::Object? = dynamic> on core::int { } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension InvalidExtensionTypeParameterCount3<T extends core::Object? = dynamic, S extends core::Object? = dynamic> on core::int { }
diff --git a/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.expect b/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.expect index d7f8e96..4f738f7 100644 --- a/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.expect +++ b/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.expect
@@ -27,8 +27,8 @@ external method /* from org-dartlang-testcase:///patch_lib.dart */ method<@#C22 S extends core::Object? = dynamic>() → void; } @#C24 -@#C6 -@#C26 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C6 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C26 extension Extension<@#C28 @/* from org-dartlang-testcase:///patch_lib.dart */ #C30 T extends core::Object? = dynamic> on core::int { method method = self2::Extension|method; method tearoff method = self2::Extension|get#method;
diff --git a/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.modular.expect b/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.modular.expect index d7f8e96..4f738f7 100644 --- a/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.modular.expect +++ b/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.modular.expect
@@ -27,8 +27,8 @@ external method /* from org-dartlang-testcase:///patch_lib.dart */ method<@#C22 S extends core::Object? = dynamic>() → void; } @#C24 -@#C6 -@#C26 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C6 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C26 extension Extension<@#C28 @/* from org-dartlang-testcase:///patch_lib.dart */ #C30 T extends core::Object? = dynamic> on core::int { method method = self2::Extension|method; method tearoff method = self2::Extension|get#method;
diff --git a/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.outline.expect b/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.outline.expect index 31a0196..8b0793c 100644 --- a/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.outline.expect +++ b/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.outline.expect
@@ -28,8 +28,8 @@ external method /* from org-dartlang-testcase:///patch_lib.dart */ method<@core::pragma::_("patch-method-type-variable") S extends core::Object? = dynamic>() → void; } @core::pragma::_("origin-extension") -@_in::patch -@core::pragma::_("patch-extension") +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ const core::pragma::_("patch-extension") extension Extension<@core::pragma::_("origin-extension-type-variable") @/* from org-dartlang-testcase:///patch_lib.dart */ const core::pragma::_("patch-extension-type-variable") T extends core::Object? = dynamic> on core::int { method method = self2::Extension|method; method tearoff method = self2::Extension|get#method; @@ -57,8 +57,8 @@ Evaluated: ConstructorInvocation @ org-dartlang-testcase:///patch_lib.dart:16:4 -> InstanceConstant(const pragma{pragma.name: "patch-procedure", pragma.options: null}) Evaluated: ConstructorInvocation @ org-dartlang-testcase:///patch_lib.dart:17:25 -> InstanceConstant(const pragma{pragma.name: "patch-method-type-variable", pragma.options: null}) Evaluated: ConstructorInvocation @ org-dartlang-testcase:///origin_lib.dart:17:2 -> InstanceConstant(const pragma{pragma.name: "origin-extension", pragma.options: null}) -Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:18:19 -> InstanceConstant(const _Patch{}) -Evaluated: ConstructorInvocation @ org-dartlang-testcase:///origin_lib.dart:18:26 -> InstanceConstant(const pragma{pragma.name: "patch-extension", pragma.options: null}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:20:1 -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:21:1 -> InstanceConstant(const pragma{pragma.name: "patch-extension", pragma.options: null}) Evaluated: ConstructorInvocation @ org-dartlang-testcase:///origin_lib.dart:18:22 -> InstanceConstant(const pragma{pragma.name: "origin-extension-type-variable", pragma.options: null}) Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:22:21 -> InstanceConstant(const pragma{pragma.name: "patch-extension-type-variable", pragma.options: null}) Evaluated: FileUriExpression @ org-dartlang-testcase:///origin_lib.dart:19:3 -> InstanceConstant(const pragma{pragma.name: "origin-extension-method", pragma.options: null})
diff --git a/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.transformed.expect index d7f8e96..4f738f7 100644 --- a/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/general/patch_annotations/main.dart.strong.transformed.expect
@@ -27,8 +27,8 @@ external method /* from org-dartlang-testcase:///patch_lib.dart */ method<@#C22 S extends core::Object? = dynamic>() → void; } @#C24 -@#C6 -@#C26 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C6 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C26 extension Extension<@#C28 @/* from org-dartlang-testcase:///patch_lib.dart */ #C30 T extends core::Object? = dynamic> on core::int { method method = self2::Extension|method; method tearoff method = self2::Extension|get#method;
diff --git a/pkg/front_end/testcases/general/patch_getter/main.dart.strong.expect b/pkg/front_end/testcases/general/patch_getter/main.dart.strong.expect index 47d3abc..16caa5b 100644 --- a/pkg/front_end/testcases/general/patch_getter/main.dart.strong.expect +++ b/pkg/front_end/testcases/general/patch_getter/main.dart.strong.expect
@@ -41,7 +41,7 @@ static get /* from org-dartlang-testcase:///patch_lib.dart */ staticGetter() → core::int return 42; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension Extension on core::int { get instanceGetter = test::Extension|get#instanceGetter; static get staticGetter = get test::Extension|staticGetter;
diff --git a/pkg/front_end/testcases/general/patch_getter/main.dart.strong.modular.expect b/pkg/front_end/testcases/general/patch_getter/main.dart.strong.modular.expect index 47d3abc..16caa5b 100644 --- a/pkg/front_end/testcases/general/patch_getter/main.dart.strong.modular.expect +++ b/pkg/front_end/testcases/general/patch_getter/main.dart.strong.modular.expect
@@ -41,7 +41,7 @@ static get /* from org-dartlang-testcase:///patch_lib.dart */ staticGetter() → core::int return 42; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension Extension on core::int { get instanceGetter = test::Extension|get#instanceGetter; static get staticGetter = get test::Extension|staticGetter;
diff --git a/pkg/front_end/testcases/general/patch_getter/main.dart.strong.outline.expect b/pkg/front_end/testcases/general/patch_getter/main.dart.strong.outline.expect index 9c86dfe..26bafaa 100644 --- a/pkg/front_end/testcases/general/patch_getter/main.dart.strong.outline.expect +++ b/pkg/front_end/testcases/general/patch_getter/main.dart.strong.outline.expect
@@ -32,7 +32,7 @@ static get /* from org-dartlang-testcase:///patch_lib.dart */ staticGetter() → core::int ; } -@_in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch extension Extension on core::int { get instanceGetter = self2::Extension|get#instanceGetter; static get staticGetter = get self2::Extension|staticGetter; @@ -56,7 +56,7 @@ Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:11:1 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:13:4 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:16:4 -> InstanceConstant(const _Patch{}) -Evaluated: StaticGet @ org-dartlang-testcase:///origin_lib.dart:18:9 -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:20:1 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:8:2 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:22:4 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:25:4 -> InstanceConstant(const _Patch{})
diff --git a/pkg/front_end/testcases/general/patch_getter/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/patch_getter/main.dart.strong.transformed.expect index 47d3abc..16caa5b 100644 --- a/pkg/front_end/testcases/general/patch_getter/main.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/general/patch_getter/main.dart.strong.transformed.expect
@@ -41,7 +41,7 @@ static get /* from org-dartlang-testcase:///patch_lib.dart */ staticGetter() → core::int return 42; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension Extension on core::int { get instanceGetter = test::Extension|get#instanceGetter; static get staticGetter = get test::Extension|staticGetter;
diff --git a/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.expect b/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.expect index 5d808e7..bb4c56c 100644 --- a/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.expect +++ b/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.expect
@@ -27,7 +27,7 @@ method /* from org-dartlang-testcase:///patch_lib.dart */ method() → core::int return #C2; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension Extension on core::int { method method = test::Extension|method; method tearoff method = test::Extension|get#method;
diff --git a/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.modular.expect b/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.modular.expect index 5d808e7..bb4c56c 100644 --- a/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.modular.expect +++ b/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.modular.expect
@@ -27,7 +27,7 @@ method /* from org-dartlang-testcase:///patch_lib.dart */ method() → core::int return #C2; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension Extension on core::int { method method = test::Extension|method; method tearoff method = test::Extension|get#method;
diff --git a/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.outline.expect b/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.outline.expect index a6c4484..acd48ff 100644 --- a/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.outline.expect +++ b/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.outline.expect
@@ -23,7 +23,7 @@ method /* from org-dartlang-testcase:///patch_lib.dart */ method() → core::int ; } -@_in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch extension Extension on core::int { method method = self2::Extension|method; method tearoff method = self2::Extension|get#method; @@ -46,6 +46,6 @@ Extra constant evaluation status: Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:9:1 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:13:4 -> InstanceConstant(const _Patch{}) -Evaluated: StaticGet @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:17:1 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:21:4 -> InstanceConstant(const _Patch{}) Extra constant evaluation: evaluated: 7, effectively constant: 4
diff --git a/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.transformed.expect index 5d808e7..bb4c56c 100644 --- a/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/general/patch_prefix_access/main.dart.strong.transformed.expect
@@ -27,7 +27,7 @@ method /* from org-dartlang-testcase:///patch_lib.dart */ method() → core::int return #C2; } -@#C1 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C1 extension Extension on core::int { method method = test::Extension|method; method tearoff method = test::Extension|get#method;
diff --git a/pkg/front_end/testcases/general/patching/main.dart.strong.expect b/pkg/front_end/testcases/general/patching/main.dart.strong.expect index 458525f..7735314 100644 --- a/pkg/front_end/testcases/general/patching/main.dart.strong.expect +++ b/pkg/front_end/testcases/general/patching/main.dart.strong.expect
@@ -114,7 +114,7 @@ static set staticSetter(core::int value) → void {} static method staticMethod(core::int value) → void {} } -@#C8 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C8 extension Extension on test::Class { get extensionInstanceGetter = test::Extension|get#extensionInstanceGetter; method extensionInstanceMethod = test::Extension|extensionInstanceMethod;
diff --git a/pkg/front_end/testcases/general/patching/main.dart.strong.modular.expect b/pkg/front_end/testcases/general/patching/main.dart.strong.modular.expect index 458525f..7735314 100644 --- a/pkg/front_end/testcases/general/patching/main.dart.strong.modular.expect +++ b/pkg/front_end/testcases/general/patching/main.dart.strong.modular.expect
@@ -114,7 +114,7 @@ static set staticSetter(core::int value) → void {} static method staticMethod(core::int value) → void {} } -@#C8 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C8 extension Extension on test::Class { get extensionInstanceGetter = test::Extension|get#extensionInstanceGetter; method extensionInstanceMethod = test::Extension|extensionInstanceMethod;
diff --git a/pkg/front_end/testcases/general/patching/main.dart.strong.outline.expect b/pkg/front_end/testcases/general/patching/main.dart.strong.outline.expect index 012cc63..495466d 100644 --- a/pkg/front_end/testcases/general/patching/main.dart.strong.outline.expect +++ b/pkg/front_end/testcases/general/patching/main.dart.strong.outline.expect
@@ -93,7 +93,7 @@ static method staticMethod(core::int value) → void ; } -@_in::patch +@/* from org-dartlang-testcase:///patch_lib.dart */ _in::patch extension Extension on self2::Class { get extensionInstanceGetter = self2::Extension|get#extensionInstanceGetter; method extensionInstanceMethod = self2::Extension|extensionInstanceMethod; @@ -180,7 +180,7 @@ Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:103:4 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:108:4 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:113:4 -> InstanceConstant(const _Patch{}) -Evaluated: StaticGet @ (unknown position in org-dartlang-testcase:///origin_lib.dart) -> InstanceConstant(const _Patch{}) +Evaluated: FileUriExpression @ org-dartlang-testcase:///patch_lib.dart:134:1 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:8:2 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:13:2 -> InstanceConstant(const _Patch{}) Evaluated: StaticGet @ org-dartlang-testcase:///patch_lib.dart:18:2 -> InstanceConstant(const _Patch{})
diff --git a/pkg/front_end/testcases/general/patching/main.dart.strong.transformed.expect b/pkg/front_end/testcases/general/patching/main.dart.strong.transformed.expect index 458525f..7735314 100644 --- a/pkg/front_end/testcases/general/patching/main.dart.strong.transformed.expect +++ b/pkg/front_end/testcases/general/patching/main.dart.strong.transformed.expect
@@ -114,7 +114,7 @@ static set staticSetter(core::int value) → void {} static method staticMethod(core::int value) → void {} } -@#C8 +@/* from org-dartlang-testcase:///patch_lib.dart */ #C8 extension Extension on test::Class { get extensionInstanceGetter = test::Extension|get#extensionInstanceGetter; method extensionInstanceMethod = test::Extension|extensionInstanceMethod;
diff --git a/pkg/record_use/CHANGELOG.md b/pkg/record_use/CHANGELOG.md index cfd2549..8d3da5f 100644 --- a/pkg/record_use/CHANGELOG.md +++ b/pkg/record_use/CHANGELOG.md
@@ -1,6 +1,8 @@ -## 0.3.1-wip +## 0.4.0 - Update SDK constraint to `^3.5.0`. +- Rewrite API to expose less symbols. +- Remove locations for easier caching. ## 0.3.0
diff --git a/pkg/record_use/README.md b/pkg/record_use/README.md index 7371b29..e3c6f85 100644 --- a/pkg/record_use/README.md +++ b/pkg/record_use/README.md
@@ -104,5 +104,14 @@ } ``` +## Limitations +As this is designed to work on both web and native platforms, we have to adapt +to the platform pecularities. One of them is that javascript does not support +named arguments, so the dart2js compiler rewrites functions to only accept named +parameters. +While you can use named parameters to record functions, we advise caution as the +retrieval behavior might change once we work around this dart2js limitation and +implement separate positional and named parameters. + ## Contributing -Contributions are welcome! Please open an issue or submit a pull request. \ No newline at end of file +Contributions are welcome! Please open an issue or submit a pull request.
diff --git a/pkg/record_use/example/record_use_example.dart b/pkg/record_use/example/record_use_example.dart index f3359cc..688d9e0 100644 --- a/pkg/record_use/example/record_use_example.dart +++ b/pkg/record_use/example/record_use_example.dart
@@ -4,9 +4,14 @@ import 'package:record_use/record_use.dart'; -void doStuff(RecordedUsages usage, Identifier callId, Identifier referenceId) { +void doStuffInLinkHook( + RecordedUsages usage, + Identifier identifier1, + Identifier identifier2, + Identifier identifier3, +) { print(usage.metadata); - print(usage.argumentsTo(callId)); - print(usage.instancesOf(referenceId)); - print(usage.hasNonConstArguments(callId)); + print(usage.constArgumentsFor(identifier1, 'void foo(int i)')); + print(usage.constantsOf(identifier2)); + print(usage.hasNonConstArguments(identifier3)); }
diff --git a/pkg/record_use/lib/record_use.dart b/pkg/record_use/lib/record_use.dart index 30c7561..3f51793 100644 --- a/pkg/record_use/lib/record_use.dart +++ b/pkg/record_use/lib/record_use.dart
@@ -2,22 +2,6 @@ // 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. -export 'src/public/arguments.dart' - show Arguments, ConstArguments, NonConstArguments; -export 'src/public/constant.dart' - show - BoolConstant, - Constant, - InstanceConstant, - IntConstant, - ListConstant, - MapConstant, - NullConstant, - PrimitiveConstant, - StringConstant; -export 'src/public/identifier.dart' show Identifier; -export 'src/public/location.dart' show Location; -export 'src/public/metadata.dart' show Metadata; -//Not exporting `Reference` as it is not used in the API -export 'src/public/reference.dart' show CallReference, InstanceReference; -export 'src/record_use.dart' show RecordedUsages; +export 'src/identifier.dart' show Identifier; +export 'src/metadata.dart' show Metadata, MetadataExt; +export 'src/record_use.dart' show ConstantInstance, RecordedUsages;
diff --git a/pkg/record_use/lib/record_use_internal.dart b/pkg/record_use/lib/record_use_internal.dart index eb97752..6f341ee 100644 --- a/pkg/record_use/lib/record_use_internal.dart +++ b/pkg/record_use/lib/record_use_internal.dart
@@ -2,7 +2,23 @@ // 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. -export 'record_use.dart'; -export 'src/internal/definition.dart' show Definition; -export 'src/internal/usage.dart' show Usage; -export 'src/internal/usage_record.dart' show UsageRecord; +export 'src/constant.dart' + show + BoolConstant, + Constant, + InstanceConstant, + IntConstant, + ListConstant, + MapConstant, + NullConstant, + PrimitiveConstant, + StringConstant; +export 'src/definition.dart' show Definition; +export 'src/identifier.dart' show Identifier; +export 'src/location.dart' show Location; +export 'src/metadata.dart' show Metadata, MetadataExt; +export 'src/record_use.dart' show RecordedUsages; +export 'src/recordings.dart' show Recordings; +export 'src/reference.dart' + show CallReference, CallTearOff, CallWithArguments, InstanceReference; +export 'src/signature.dart' show Signature;
diff --git a/pkg/record_use/lib/src/constant.dart b/pkg/record_use/lib/src/constant.dart new file mode 100644 index 0000000..81e0dfd --- /dev/null +++ b/pkg/record_use/lib/src/constant.dart
@@ -0,0 +1,262 @@ +// Copyright (c) 2024, 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 'helper.dart'; + +const _typeKey = 'type'; +const _valueKey = 'value'; + +/// A constant value that can be recorded and serialized. +/// +/// This supports basic constants such as [bool]s or [int]s, as well as +/// [ListConstant], [MapConstant] or [InstanceConstant] for more complex +/// structures. +/// +/// This follows the AST constant concept from the Dart SDK. +sealed class Constant { + /// Creates a [Constant] object. + const Constant(); + + /// Converts this [Constant] object to a JSON representation. + /// + /// [constants] needs to be passed, as the [Constant]s are normalized and + /// stored separately in the JSON. + Map<String, Object?> toJson(Map<Constant, int> constants); + + /// Converts this [Constant] to the value it represents. + Object? toValue() => switch (this) { + NullConstant() => null, + PrimitiveConstant p => p.value, + ListConstant<Constant> l => l.value.map((c) => c.toValue()).toList(), + MapConstant<Constant> m => m.value.map( + (key, value) => MapEntry(key, value.toValue()), + ), + InstanceConstant i => i.fields.map( + (key, value) => MapEntry(key, value.toValue()), + ), + }; + + /// Creates a [Constant] object from its JSON representation. + /// + /// [constants] needs to be passed, as the [Constant]s are normalized and + /// stored separately in the JSON. + static Constant fromJson( + Map<String, Object?> value, + List<Constant> constants, + ) => switch (value[_typeKey] as String) { + NullConstant._type => const NullConstant(), + BoolConstant._type => BoolConstant(value[_valueKey] as bool), + IntConstant._type => IntConstant(value[_valueKey] as int), + StringConstant._type => StringConstant(value[_valueKey] as String), + ListConstant._type => ListConstant( + (value[_valueKey] as List<dynamic>) + .map((value) => value as int) + .map((value) => constants[value]) + .toList(), + ), + MapConstant._type => MapConstant( + (value[_valueKey] as Map<String, Object?>).map( + (key, value) => MapEntry(key, constants[value as int]), + ), + ), + InstanceConstant._type => InstanceConstant( + fields: (value[_valueKey] as Map<String, Object?>).map( + (key, value) => MapEntry(key, constants[value as int]), + ), + ), + String() => + throw UnimplementedError('This type is not a supported constant'), + }; +} + +/// Represents the `null` constant value. +final class NullConstant extends Constant { + /// The type identifier for JSON serialization. + static const _type = 'Null'; + + /// Creates a [NullConstant] object. + const NullConstant() : super(); + + @override + Map<String, Object?> toJson(Map<Constant, int> constants) => + _toJson(_type, null); + + @override + bool operator ==(Object other) => other is NullConstant; + + @override + int get hashCode => 0; +} + +/// Represents a constant value of a primitive type. +sealed class PrimitiveConstant<T extends Object> extends Constant { + /// The underlying value of this constant. + final T value; + + /// Creates a [PrimitiveConstant] object with the given [value]. + const PrimitiveConstant(this.value); + + @override + int get hashCode => value.hashCode; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is PrimitiveConstant<T> && other.value == value; + } + + @override + Map<String, Object?> toJson(Map<Constant, int> constants) => valueToJson(); + + /// Converts this primitive constant to a JSON representation. + Map<String, Object?> valueToJson(); +} + +/// Represents a constant boolean value. +final class BoolConstant extends PrimitiveConstant<bool> { + /// The type identifier for JSON serialization. + static const _type = 'bool'; + + /// Creates a [BoolConstant] object with the given boolean [value]. + const BoolConstant(super.value); + + @override + Map<String, Object?> valueToJson() => _toJson(_type, value); +} + +/// Represents a constant integer value. +final class IntConstant extends PrimitiveConstant<int> { + /// The type identifier for JSON serialization. + static const _type = 'int'; + + /// Creates an [IntConstant] object with the given integer [value]. + const IntConstant(super.value); + + @override + Map<String, Object?> valueToJson() => _toJson(_type, value); +} + +/// Represents a constant string value. +final class StringConstant extends PrimitiveConstant<String> { + /// The type identifier for JSON serialization. + static const _type = 'String'; + + /// Creates a [StringConstant] object with the given string [value]. + const StringConstant(super.value); + + @override + Map<String, Object?> valueToJson() => _toJson(_type, value); +} + +/// Represents a constant list of [Constant] values. +final class ListConstant<T extends Constant> extends Constant { + /// The type identifier for JSON serialization. + static const _type = 'list'; + + /// The underlying list of constant values. + final List<T> value; + + /// Creates a [ListConstant] object with the given list of [value]s. + const ListConstant(this.value); + + @override + int get hashCode => deepHash(value); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is ListConstant && deepEquals(other.value, value); + } + + @override + Map<String, Object?> toJson(Map<Constant, int> constants) => + _toJson(_type, value.map((constant) => constants[constant]).toList()); +} + +/// Represents a constant map from string keys to [Constant] values. +final class MapConstant<T extends Constant> extends Constant { + /// The type identifier for JSON serialization. + static const _type = 'map'; + + /// The underlying map of constant values. + final Map<String, T> value; + + /// Creates a [MapConstant] object with the given map of [value]s. + const MapConstant(this.value); + + @override + int get hashCode => deepHash(value); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is MapConstant && deepEquals(other.value, value); + } + + @override + Map<String, Object?> toJson(Map<Constant, int> constants) => _toJson( + _type, + value.map((key, constant) => MapEntry(key, constants[constant]!)), + ); +} + +/// A constant instance of a class with its fields +/// +/// Only as far as they can also be represented by constants. This is more or +/// less the same as a [MapConstant]. +final class InstanceConstant extends Constant { + /// The type identifier for JSON serialization. + static const _type = 'Instance'; + + /// The fields of this instance, mapped from field name to [Constant] value. + final Map<String, Constant> fields; + + /// Creates an [InstanceConstant] object with the given [fields]. + const InstanceConstant({required this.fields}); + + /// Creates an [InstanceConstant] object from JSON. + /// + /// [json] is a map representing the JSON structure. + /// [constants] is a list of [Constant] objects that are referenced by index + /// in the JSON. + factory InstanceConstant.fromJson( + Map<String, Object?> json, + List<Constant> constants, + ) { + return InstanceConstant( + fields: json.map( + (key, constantIndex) => MapEntry(key, constants[constantIndex as int]), + ), + ); + } + + @override + Map<String, Object?> toJson(Map<Constant, int> constants) => _toJson( + _type, + fields.isNotEmpty + ? fields.map( + (name, constantIndex) => MapEntry(name, constants[constantIndex]!), + ) + : null, + ); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is InstanceConstant && deepEquals(other.fields, fields); + } + + @override + int get hashCode => deepHash(fields); +} + +/// Helper to create the JSON structure of constants by storing the value with +/// the type. +Map<String, Object?> _toJson(String type, Object? value) { + return {_typeKey: type, if (value != null) _valueKey: value}; +}
diff --git a/pkg/record_use/lib/src/definition.dart b/pkg/record_use/lib/src/definition.dart new file mode 100644 index 0000000..ffc04ff --- /dev/null +++ b/pkg/record_use/lib/src/definition.dart
@@ -0,0 +1,42 @@ +// Copyright (c) 2024, 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 'identifier.dart' show Identifier; + +/// A defintion is an [identifier] with its [loadingUnit]. +class Definition { + final Identifier identifier; + final String? loadingUnit; + + const Definition({required this.identifier, this.loadingUnit}); + + static const _identifierKey = 'identifier'; + static const _loadingUnitKey = 'loading_unit'; + + factory Definition.fromJson(Map<String, Object?> json) { + return Definition( + identifier: Identifier.fromJson( + json[_identifierKey] as Map<String, Object?>, + ), + loadingUnit: json[_loadingUnitKey] as String?, + ); + } + + Map<String, Object?> toJson() => { + _identifierKey: identifier.toJson(), + if (loadingUnit != null) _loadingUnitKey: loadingUnit, + }; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is Definition && + other.identifier == identifier && + other.loadingUnit == loadingUnit; + } + + @override + int get hashCode => Object.hash(identifier, loadingUnit); +}
diff --git a/pkg/record_use/lib/src/identifier.dart b/pkg/record_use/lib/src/identifier.dart new file mode 100644 index 0000000..b50a730 --- /dev/null +++ b/pkg/record_use/lib/src/identifier.dart
@@ -0,0 +1,68 @@ +// Copyright (c) 2024, 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. + +/// Represents a unique identifier for a code element, such as a class, method, +/// or field, within a Dart program. +/// +/// An [Identifier] is used to pinpoint a specific element based on its +/// location and name. It consists of: +/// +/// - `importUri`: The URI of the library where the element is defined. +/// - `parent`: The name of the parent element (e.g., the class name for a +/// method or field). This is optional, as not all elements have parents (e.g. +/// top-level functions). +/// - `name`: The name of the element itself. +class Identifier { + /// The URI of the library where the element is defined. + /// + /// This is given in the form of its package import uri, so that it is OS- and + /// user independent. + final String importUri; + + /// The name of the parent element (e.g., the class name for a method or + /// field). This is optional, as not all elements have parents (e.g. top-level + /// functions). + final String? scope; + + /// The name of the element itself. + final String name; + + /// Creates an [Identifier] object. + /// + /// [importUri] is the URI of the library where the element is defined. + /// [scope] is the optional name of the parent element. + /// [name] is the name of the element. + const Identifier({required this.importUri, this.scope, required this.name}); + + static const String _uriKey = 'uri'; + static const String _scopeKey = 'scope'; + static const String _nameKey = 'name'; + + /// Creates an [Identifier] object from its JSON representation. + factory Identifier.fromJson(Map<String, Object?> json) => Identifier( + importUri: json[_uriKey] as String, + scope: json[_scopeKey] as String?, + name: json[_nameKey] as String, + ); + + /// Converts this [Identifier] object to a JSON representation. + Map<String, Object?> toJson() => { + _uriKey: importUri, + if (scope != null) _scopeKey: scope, + _nameKey: name, + }; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is Identifier && + other.importUri == importUri && + other.scope == scope && + other.name == name; + } + + @override + int get hashCode => Object.hash(importUri, scope, name); +}
diff --git a/pkg/record_use/lib/src/internal/definition.dart b/pkg/record_use/lib/src/internal/definition.dart deleted file mode 100644 index 5b53b32..0000000 --- a/pkg/record_use/lib/src/internal/definition.dart +++ /dev/null
@@ -1,56 +0,0 @@ -// Copyright (c) 2024, 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 '../public/identifier.dart'; -import '../public/location.dart'; - -class Definition { - final Identifier identifier; - - /// Represents the '@' field in the JSON - final Location location; - final String? loadingUnit; - - const Definition({ - required this.identifier, - required this.location, - this.loadingUnit, - }); - - factory Definition.fromJson( - Map<String, dynamic> json, - List<Identifier> identifiers, - List<String> uris, - ) { - final identifier = identifiers[json['id'] as int]; - return Definition( - identifier: identifier, - location: Location.fromJson(json['@'] as Map<String, dynamic>, uris), - loadingUnit: json['loadingUnit'] as String?, - ); - } - - Map<String, dynamic> toJson( - Map<Identifier, int> identifiers, - Map<String, int> uris, - ) => - { - 'id': identifiers[identifier]!, - '@': location.toJson(uris), - 'loadingUnit': loadingUnit, - }; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is Definition && - other.identifier == identifier && - other.location == location && - other.loadingUnit == loadingUnit; - } - - @override - int get hashCode => Object.hash(identifier, location, loadingUnit); -}
diff --git a/pkg/record_use/lib/src/internal/usage.dart b/pkg/record_use/lib/src/internal/usage.dart deleted file mode 100644 index ff8b093..0000000 --- a/pkg/record_use/lib/src/internal/usage.dart +++ /dev/null
@@ -1,59 +0,0 @@ -// Copyright (c) 2024, 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 '../helper.dart'; -import '../public/constant.dart'; -import '../public/identifier.dart'; -import '../public/reference.dart'; -import 'definition.dart'; - -class Usage<T extends Reference> { - final Definition definition; - final List<T> references; - - const Usage({ - required this.definition, - required this.references, - }); - - factory Usage.fromJson( - Map<String, dynamic> json, - List<Identifier> identifiers, - List<String> uris, - List<Constant> constants, - T Function(Map<String, dynamic>, List<String>, List<Constant>) constr, - ) => - Usage( - definition: Definition.fromJson( - json['definition'] as Map<String, dynamic>, - identifiers, - uris, - ), - references: (json['references'] as List) - .map((x) => constr(x as Map<String, dynamic>, uris, constants)) - .toList(), - ); - - Map<String, dynamic> toJson( - Map<Identifier, int> identifiers, - Map<String, int> uris, - Map<Constant, int> constants, - ) => - { - 'definition': definition.toJson(identifiers, uris), - 'references': references.map((x) => x.toJson(uris, constants)).toList(), - }; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is Usage<T> && - other.definition == definition && - deepEquals(other.references, references); - } - - @override - int get hashCode => Object.hash(definition, deepHash(references)); -}
diff --git a/pkg/record_use/lib/src/internal/usage_record.dart b/pkg/record_use/lib/src/internal/usage_record.dart deleted file mode 100644 index ba63a3a..0000000 --- a/pkg/record_use/lib/src/internal/usage_record.dart +++ /dev/null
@@ -1,147 +0,0 @@ -// Copyright (c) 2024, 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:collection/collection.dart'; - -import '../helper.dart'; -import '../public/arguments.dart'; -import '../public/constant.dart'; -import '../public/identifier.dart'; -import '../public/metadata.dart'; -import '../public/reference.dart'; -import 'usage.dart'; - -class UsageRecord { - final Metadata metadata; - final List<Usage<CallReference>> calls; - final List<Usage<InstanceReference>> instances; - - const UsageRecord({ - required this.metadata, - required this.calls, - required this.instances, - }); - - factory UsageRecord.fromJson(Map<String, dynamic> json) { - final uris = (json['uris'] as List).cast<String>(); - - final identifiers = (json['ids'] as List) - .whereType<Map<String, dynamic>>() - .map( - (e) => Identifier.fromJson(e, uris), - ) - .toList(); - - final constants = <Constant>[]; - for (var constantJsonObj in json['constants'] as List) { - var constantJson = constantJsonObj as Map<String, dynamic>; - constants.add(Constant.fromJson(constantJson, constants)); - } - - return UsageRecord( - metadata: Metadata.fromJson(json['metadata'] as Map<String, dynamic>), - calls: (json['calls'] as List?) - ?.map((x) => Usage.fromJson( - x as Map<String, dynamic>, - identifiers, - uris, - constants, - CallReference.fromJson, - )) - .toList() ?? - [], - instances: (json['instances'] as List?) - ?.map((x) => Usage.fromJson( - x as Map<String, dynamic>, - identifiers, - uris, - constants, - InstanceReference.fromJson, - )) - .toList() ?? - [], - ); - } - - Map<String, dynamic> toJson() { - final identifiers = <Identifier>{ - ...calls.map((call) => call.definition.identifier), - ...instances.map((instance) => instance.definition.identifier), - }.asMapToIndices; - - final uris = <String>{ - ...identifiers.keys.map((e) => e.importUri), - ...calls.expand((call) => [ - call.definition.location.uri, - ...call.references.map((reference) => reference.location.uri), - ]), - ...instances.expand((instance) => [ - instance.definition.location.uri, - ...instance.references.map((reference) => reference.location.uri), - ]), - }.asMapToIndices; - - final constants = { - ...calls.expand((e) => e.references - .map((e) => e.arguments?.constArguments) - .whereType<ConstArguments>() - .expand((e) => {...e.named.values, ...e.positional.values})), - ...instances.expand((element) => element.references).expand((e) => { - ...e.instanceConstant.fields.values, - e.instanceConstant, - }) - }.flatten().asMapToIndices; - return { - 'metadata': metadata.toJson(), - 'uris': uris.keys.toList(), - 'ids': identifiers.keys - .map((identifier) => identifier.toJson(uris)) - .toList(), - 'constants': - constants.keys.map((constant) => constant.toJson(constants)).toList(), - if (calls.isNotEmpty) - 'calls': calls - .map((reference) => reference.toJson(identifiers, uris, constants)) - .toList(), - if (instances.isNotEmpty) - 'instances': instances - .map((reference) => reference.toJson(identifiers, uris, constants)) - .toList(), - }; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is UsageRecord && - other.metadata == metadata && - deepEquals(other.calls, calls) && - deepEquals(other.instances, instances); - } - - @override - int get hashCode => - Object.hash(metadata, deepHash(calls), deepHash(instances)); -} - -extension on Iterable<Constant> { - Set<Constant> flatten() { - final constants = <Constant>{}; - for (var constant in this) { - constants.addAll(switch (constant) { - ListConstant<Constant> list => [...list.value.flatten(), list], - MapConstant<Constant> map => [...map.value.values.flatten(), map], - Constant() => {constant}, - }); - } - return constants; - } -} - -extension _PrivateIterableExtension<T> on Iterable<T> { - Map<T, int> get asMapToIndices => Map.fromEntries( - mapIndexed((index, uri) => MapEntry(uri, index)), - ); -}
diff --git a/pkg/record_use/lib/src/location.dart b/pkg/record_use/lib/src/location.dart new file mode 100644 index 0000000..73ce20605 --- /dev/null +++ b/pkg/record_use/lib/src/location.dart
@@ -0,0 +1,44 @@ +// Copyright (c) 2024, 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. + +class Location { + final String uri; + final int? line; + final int? column; + + const Location({required this.uri, this.line, this.column}); + + static const _uriKey = 'uri'; + static const _lineKey = 'line'; + static const _columnKey = 'column'; + + factory Location.fromJson(Map<String, Object?> map) { + return Location( + uri: map[_uriKey] as String, + line: map[_lineKey] as int?, + column: map[_columnKey] as int?, + ); + } + + Map<String, Object?> toJson() { + return { + _uriKey: uri, + if (line != null) _lineKey: line, + if (line != null) _columnKey: column, + }; + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is Location && + other.uri == uri && + other.line == line && + other.column == column; + } + + @override + int get hashCode => Object.hash(uri, line, column); +}
diff --git a/pkg/record_use/lib/src/metadata.dart b/pkg/record_use/lib/src/metadata.dart new file mode 100644 index 0000000..819b614 --- /dev/null +++ b/pkg/record_use/lib/src/metadata.dart
@@ -0,0 +1,41 @@ +// Copyright (c) 2024, 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:pub_semver/pub_semver.dart'; + +import 'helper.dart'; + +/// Metadata attached to a recorded usages file. +/// +/// Whatever [Metadata] should be added to the usage recording. Care should be +/// applied to not include non-deterministic or dynamic data such as timestamps, +/// as this would mess with the usage recording caching. +class Metadata { + /// The underlying data. + /// + /// Together with the metadata extension [MetadataExt], this makes the + /// metadata extensible by the user implementing the recording. For example, + /// dart2js might want to store different metadata than the Dart VM. + final Map<String, Object?> json; + + const Metadata._({required this.json}); + + factory Metadata.fromJson(Map<String, Object?> json) => + Metadata._(json: json); + + @override + bool operator ==(covariant Metadata other) { + if (identical(this, other)) return true; + + return deepEquals(other.json, json); + } + + @override + int get hashCode => deepHash(json); +} + +extension MetadataExt on Metadata { + Version get version => Version.parse(json['version'] as String); + String get comment => json['comment'] as String; +}
diff --git a/pkg/record_use/lib/src/public/arguments.dart b/pkg/record_use/lib/src/public/arguments.dart deleted file mode 100644 index 8b20ea3..0000000 --- a/pkg/record_use/lib/src/public/arguments.dart +++ /dev/null
@@ -1,138 +0,0 @@ -// Copyright (c) 2024, 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 '../helper.dart'; -import 'constant.dart'; - -class Arguments { - final ConstArguments constArguments; - final NonConstArguments nonConstArguments; - - const Arguments({ - ConstArguments? constArguments, - NonConstArguments? nonConstArguments, - }) : constArguments = constArguments ?? const ConstArguments(), - nonConstArguments = nonConstArguments ?? const NonConstArguments(); - - factory Arguments.fromJson( - Map<String, dynamic> json, - List<Constant> constants, - ) { - final constJson = json['const'] as Map<String, dynamic>?; - final nonConstJson = json['nonConst'] as Map<String, dynamic>?; - return Arguments( - constArguments: constJson != null - ? ConstArguments.fromJson(constJson, constants) - : null, - nonConstArguments: nonConstJson != null - ? NonConstArguments.fromJson(nonConstJson) - : null, - ); - } - - Map<String, dynamic> toJson(Map<Constant, int> constants) { - final hasConst = - constArguments.named.isNotEmpty || constArguments.positional.isNotEmpty; - final hasNonConst = nonConstArguments.named.isNotEmpty || - nonConstArguments.positional.isNotEmpty; - return { - if (hasConst) 'const': constArguments.toJson(constants), - if (hasNonConst) 'nonConst': nonConstArguments.toJson(), - }; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is Arguments && - other.constArguments == constArguments && - other.nonConstArguments == nonConstArguments; - } - - @override - int get hashCode => Object.hash(constArguments, nonConstArguments); -} - -class ConstArguments { - final Map<int, Constant> positional; - final Map<String, Constant> named; - - const ConstArguments( - {Map<int, Constant>? positional, Map<String, Constant>? named}) - : named = named ?? const {}, - positional = positional ?? const {}; - - factory ConstArguments.fromJson( - Map<String, dynamic> json, - List<Constant> constants, - ) => - ConstArguments( - positional: json['positional'] != null - ? (json['positional'] as Map<String, dynamic>).map((position, - constantIndex) => - MapEntry(int.parse(position), constants[constantIndex as int])) - : {}, - named: json['named'] != null - ? (json['named'] as Map<String, dynamic>).map( - (name, constantIndex) => - MapEntry(name, constants[constantIndex as int])) - : {}, - ); - - Map<String, dynamic> toJson(Map<Constant, int> constants) => { - if (positional.isNotEmpty) - 'positional': positional.map((position, constantIndex) => - MapEntry(position.toString(), constants[constantIndex]!)), - if (named.isNotEmpty) - 'named': named.map((name, constantIndex) => - MapEntry(name, constants[constantIndex]!)), - }; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is ConstArguments && - deepEquals(other.positional, positional) && - deepEquals(other.named, named); - } - - @override - int get hashCode => Object.hash(deepHash(positional), deepHash(named)); -} - -class NonConstArguments { - final List<int> positional; - final List<String> named; - - const NonConstArguments({List<int>? positional, List<String>? named}) - : named = named ?? const [], - positional = positional ?? const []; - - factory NonConstArguments.fromJson(Map<String, dynamic> json) => - NonConstArguments( - positional: json['positional'] != null - ? (json['positional'] as List).cast() - : <int>[], - named: json['named'] != null ? (json['named'] as List).cast() : [], - ); - - Map<String, dynamic> toJson() => { - if (positional.isNotEmpty) 'positional': positional, - if (named.isNotEmpty) 'named': named, - }; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is NonConstArguments && - deepEquals(other.positional, positional) && - deepEquals(other.named, named); - } - - @override - int get hashCode => Object.hash(deepHash(positional), deepHash(named)); -}
diff --git a/pkg/record_use/lib/src/public/constant.dart b/pkg/record_use/lib/src/public/constant.dart deleted file mode 100644 index 2336475..0000000 --- a/pkg/record_use/lib/src/public/constant.dart +++ /dev/null
@@ -1,184 +0,0 @@ -// Copyright (c) 2024, 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 '../helper.dart'; - -sealed class Constant { - const Constant(); - - Map<String, dynamic> toJson(Map<Constant, int> constants); - - static Constant fromJson( - Map<String, dynamic> value, List<Constant> constants) => - switch (value['type'] as String) { - NullConstant._type => const NullConstant(), - BoolConstant._type => BoolConstant(value['value'] as bool), - IntConstant._type => IntConstant(value['value'] as int), - StringConstant._type => StringConstant(value['value'] as String), - ListConstant._type => ListConstant((value['value'] as List<dynamic>) - .map((value) => value as int) - .map((value) => constants[value]) - .toList()), - MapConstant._type => MapConstant( - (value['value'] as Map<String, dynamic>) - .map((key, value) => MapEntry(key, constants[value as int]))), - InstanceConstant._type => InstanceConstant( - fields: (value['value'] as Map<String, dynamic>) - .map((key, value) => MapEntry(key, constants[value as int]))), - String() => - throw UnimplementedError('This type is not a supported constant'), - }; -} - -final class NullConstant extends Constant { - static const _type = 'Null'; - - const NullConstant() : super(); - - @override - Map<String, dynamic> toJson(Map<Constant, int> constants) => - _toJson(_type, null); -} - -sealed class PrimitiveConstant<T extends Object> extends Constant { - final T value; - - const PrimitiveConstant(this.value); - - @override - int get hashCode => value.hashCode; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is PrimitiveConstant<T> && other.value == value; - } - - @override - Map<String, dynamic> toJson(Map<Constant, int> constants) => valueToJson(); - - Map<String, dynamic> valueToJson(); -} - -final class BoolConstant extends PrimitiveConstant<bool> { - static const _type = 'bool'; - - const BoolConstant(super.value); - - @override - Map<String, dynamic> valueToJson() => _toJson(_type, value); -} - -final class IntConstant extends PrimitiveConstant<int> { - static const _type = 'int'; - - const IntConstant(super.value); - - @override - Map<String, dynamic> valueToJson() => _toJson(_type, value); -} - -final class StringConstant extends PrimitiveConstant<String> { - static const _type = 'String'; - - const StringConstant(super.value); - - @override - Map<String, dynamic> valueToJson() => _toJson(_type, value); -} - -final class ListConstant<T extends Constant> extends Constant { - static const _type = 'list'; - - final List<T> value; - - const ListConstant(this.value); - - @override - int get hashCode => deepHash(value); - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is ListConstant && deepEquals(other.value, value); - } - - @override - Map<String, dynamic> toJson(Map<Constant, int> constants) => _toJson( - _type, - value.map((constant) => constants[constant]).toList(), - ); -} - -final class MapConstant<T extends Constant> extends Constant { - static const _type = 'map'; - - final Map<String, T> value; - - const MapConstant(this.value); - - @override - int get hashCode => deepHash(value); - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is MapConstant && deepEquals(other.value, value); - } - - @override - Map<String, dynamic> toJson(Map<Constant, int> constants) => _toJson( - _type, - value.map((key, constant) => MapEntry(key, constants[constant]!)), - ); -} - -final class InstanceConstant extends Constant { - static const _type = 'Instance'; - - final Map<String, Constant> fields; - - const InstanceConstant({ - required this.fields, - }); - - factory InstanceConstant.fromJson( - Map<String, dynamic> json, - List<Constant> constants, - ) { - return InstanceConstant( - fields: json.map((key, constantIndex) => - MapEntry(key, constants[constantIndex as int])), - ); - } - - @override - Map<String, dynamic> toJson(Map<Constant, int> constants) => _toJson( - _type, - fields.isNotEmpty - ? fields.map((name, constantIndex) => - MapEntry(name, constants[constantIndex]!)) - : null, - ); - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is InstanceConstant && deepEquals(other.fields, fields); - } - - @override - int get hashCode => deepHash(fields); -} - -Map<String, dynamic> _toJson(String type, Object? value) { - return { - 'type': type, - if (value != null) 'value': value, - }; -}
diff --git a/pkg/record_use/lib/src/public/identifier.dart b/pkg/record_use/lib/src/public/identifier.dart deleted file mode 100644 index 18bf720..0000000 --- a/pkg/record_use/lib/src/public/identifier.dart +++ /dev/null
@@ -1,41 +0,0 @@ -// Copyright (c) 2024, 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. - -class Identifier { - final String importUri; - final String? parent; // Optional since not all elements have parents - final String name; - - const Identifier({ - required this.importUri, - this.parent, - required this.name, - }); - - factory Identifier.fromJson(Map<String, dynamic> json, List<String> uris) => - Identifier( - importUri: uris[json['uri'] as int], - parent: json['parent'] as String?, - name: json['name'] as String, - ); - - Map<String, dynamic> toJson(Map<String, int> uris) => { - 'uri': uris[importUri]!, - if (parent != null) 'parent': parent, - 'name': name, - }; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is Identifier && - other.importUri == importUri && - other.parent == parent && - other.name == name; - } - - @override - int get hashCode => Object.hash(importUri, parent, name); -}
diff --git a/pkg/record_use/lib/src/public/location.dart b/pkg/record_use/lib/src/public/location.dart deleted file mode 100644 index f0ef6c1..0000000 --- a/pkg/record_use/lib/src/public/location.dart +++ /dev/null
@@ -1,44 +0,0 @@ -// Copyright (c) 2024, 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. - -class Location { - final String uri; - final int line; - final int column; - - const Location({ - required this.uri, - required this.line, - required this.column, - }); - - factory Location.fromJson(Map<String, dynamic> map, List<String> uris) { - return Location( - uri: uris[map['uri'] as int], - line: map['line'] as int, - column: map['column'] as int, - ); - } - - Map<String, dynamic> toJson(Map<String, int> uris) { - return { - 'uri': uris[uri]!, - 'line': line, - 'column': column, - }; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is Location && - other.uri == uri && - other.line == line && - other.column == column; - } - - @override - int get hashCode => Object.hash(uri, line, column); -}
diff --git a/pkg/record_use/lib/src/public/metadata.dart b/pkg/record_use/lib/src/public/metadata.dart deleted file mode 100644 index 62b4e70..0000000 --- a/pkg/record_use/lib/src/public/metadata.dart +++ /dev/null
@@ -1,37 +0,0 @@ -// Copyright (c) 2024, 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:pub_semver/pub_semver.dart'; - -class Metadata { - final String? comment; - final Version version; - - const Metadata({ - this.comment, - required this.version, - }); - - factory Metadata.fromJson(Map<String, dynamic> json) => Metadata( - comment: json['comment'] as String?, - version: Version.parse(json['version'] as String), - ); - - Map<String, dynamic> toJson() => { - if (comment != null) 'comment': comment, - 'version': version.toString(), - }; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is Metadata && - other.comment == comment && - other.version == version; - } - - @override - int get hashCode => Object.hash(comment, version); -}
diff --git a/pkg/record_use/lib/src/public/reference.dart b/pkg/record_use/lib/src/public/reference.dart deleted file mode 100644 index 0894380..0000000 --- a/pkg/record_use/lib/src/public/reference.dart +++ /dev/null
@@ -1,130 +0,0 @@ -// Copyright (c) 2024, 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 'arguments.dart'; -import 'constant.dart'; -import 'location.dart'; - -sealed class Reference { - final String? loadingUnit; - - /// Represents the "@" field in the JSON - final Location location; - - const Reference({this.loadingUnit, required this.location}); - - Map<String, dynamic> toJson( - Map<String, int> uris, - Map<Constant, int> constants, - ) => - { - 'loadingUnit': loadingUnit, - '@': location.toJson(uris), - }; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - - return other is Reference && - other.loadingUnit == loadingUnit && - other.location == location; - } - - @override - int get hashCode => Object.hash(loadingUnit, location); -} - -final class CallReference extends Reference { - final Arguments? arguments; - - const CallReference({ - required this.arguments, - super.loadingUnit, - required super.location, - }); - - factory CallReference.fromJson( - Map<String, dynamic> json, - List<String> uris, - List<Constant> constants, - ) { - return CallReference( - arguments: json['arguments'] != null - ? Arguments.fromJson( - json['arguments'] as Map<String, dynamic>, constants) - : null, - loadingUnit: json['loadingUnit'] as String?, - location: Location.fromJson(json['@'] as Map<String, dynamic>, uris), - ); - } - - @override - Map<String, dynamic> toJson( - Map<String, int> uris, - Map<Constant, int> constants, - ) { - final argumentJson = arguments?.toJson(constants) ?? {}; - return { - if (argumentJson.isNotEmpty) 'arguments': argumentJson, - ...super.toJson(uris, constants), - }; - } - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (!(super == other)) return false; - - return other is CallReference && other.arguments == arguments; - } - - @override - int get hashCode => Object.hash(arguments, super.hashCode); -} - -final class InstanceReference extends Reference { - final InstanceConstant instanceConstant; - - const InstanceReference({ - super.loadingUnit, - required super.location, - required this.instanceConstant, - }); - - factory InstanceReference.fromJson( - Map<String, dynamic> json, - List<String> uris, - List<Constant> constants, - ) { - return InstanceReference( - instanceConstant: - constants[json['instanceConstant'] as int] as InstanceConstant, - loadingUnit: json['loadingUnit'] as String?, - location: Location.fromJson(json['@'] as Map<String, dynamic>, uris), - ); - } - - @override - Map<String, dynamic> toJson( - Map<String, int> uris, - Map<Constant, int> constants, - ) => - { - 'instanceConstant': constants[instanceConstant]!, - ...super.toJson(uris, constants), - }; - - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; - if (!(super == other)) return false; - - return other is InstanceReference && - other.instanceConstant == instanceConstant; - } - - @override - int get hashCode => Object.hash(instanceConstant, super.hashCode); -}
diff --git a/pkg/record_use/lib/src/record_use.dart b/pkg/record_use/lib/src/record_use.dart index bb6f192..f4cbcf66 100644 --- a/pkg/record_use/lib/src/record_use.dart +++ b/pkg/record_use/lib/src/record_use.dart
@@ -2,27 +2,24 @@ // 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:collection/collection.dart'; +import '../record_use_internal.dart'; -import 'internal/usage.dart'; -import 'internal/usage_record.dart'; -import 'public/arguments.dart'; -import 'public/identifier.dart'; -import 'public/metadata.dart'; -import 'public/reference.dart'; - -extension type RecordedUsages._(UsageRecord _usages) { - RecordedUsages.fromJson(Map<String, dynamic> json) - : this._(UsageRecord.fromJson(json)); +/// Holds all information recorded during compilation. +/// +/// This can be queried using the methods provided, which each take an +/// [Identifier] which must be annotated with `@RecordUse` from `package:meta`. +extension type RecordedUsages._(Recordings _recordings) { + RecordedUsages.fromJson(Map<String, Object?> json) + : this._(Recordings.fromJson(json)); /// Show the metadata for this recording of usages. - Metadata get metadata => _usages.metadata; + Metadata get metadata => _recordings.metadata; - /// Finds all const arguments for calls to the [method]. + /// Finds all const arguments for calls to the [identifier]. /// /// The definition must be annotated with `@RecordUse()`. If there are no /// calls to the definition, either because it was treeshaken, because it was - /// not annotated, or because it does not exist, returns `null`. + /// not annotated, or because it does not exist, returns empty. /// /// Returns an empty iterable if the arguments were not collected. /// @@ -48,20 +45,32 @@ /// parent: 'SomeClass', /// name: 'someStaticMethod'), /// ).first == - /// Arguments( - /// constArguments: ConstArguments(positional: {1: IntConstant(42)}), - /// ); + /// [ + /// {1: 42} + /// ] /// ``` - Iterable<Arguments>? argumentsTo(Identifier method) => _callTo(method) - ?.references - .map((reference) => reference.arguments) - .whereType(); + Iterable<({Map<String, Object?> named, List<Object?> positional})> + constArgumentsFor(Identifier identifier, String signature) { + return _recordings.calls[identifier]?.whereType<CallWithArguments>().map(( + call, + ) { + final (:named, :positional) = Signature.parseMethodSignature( + signature, + ).parseArguments(call); + named.removeWhere((key, value) => value == null); + return ( + named: named.map((key, value) => MapEntry(key, value?.toValue())), + positional: positional.nonNulls.map((e) => e.toValue()).toList(), + ); + }) ?? + []; + } - /// Finds all fields of a const instance of the class at [classIdentifier]. + /// Finds all constant fields of a const instance of the class [identifier]. /// /// The definition must be annotated with `@RecordUse()`. If there are /// no instances of the definition, either because it was treeshaken, because - /// it was not annotated, or because it does not exist, returns `null`. + /// it was not annotated, or because it does not exist, returns empty. /// /// The types of fields supported are defined at /// @@ -78,7 +87,7 @@ /// } /// } /// - /// @ResourceIdentifier() + /// @RecordUse() /// class AnnotationClass { /// final String s; /// const AnnotationClass(this.s); @@ -87,40 +96,46 @@ /// /// Would mean that /// ``` - /// instancesOf(Identifier( + /// constantsOf(Identifier( /// uri: 'path/to/file.dart', /// name: 'AnnotationClass'), - /// ).first.instanceConstant == - /// [ - /// InstanceConstant(fields: {'s': 'freddie'}) - /// ]; + /// ).first['s'] == 'freddie'; /// ``` /// /// What kinds of fields can be recorded depends on the implementation of /// https://dart-review.googlesource.com/c/sdk/+/369620/13/pkg/vm/lib/transformations/record_use/record_instance.dart - Iterable<InstanceReference>? instancesOf(Identifier classIdentifier) => - _usages.instances - .firstWhereOrNull( - (instance) => instance.definition.identifier == classIdentifier) - ?.references; + Iterable<ConstantInstance> constantsOf(Identifier identifier) { + return _recordings.instances[identifier]?.map( + (reference) => ConstantInstance(reference.instanceConstant.fields), + ) ?? + []; + } - /// Checks if any call to [method] has non-const arguments. + /// Checks if any call to [identifier] has non-const arguments, or if any + /// tear-off was recorded. /// /// The definition must be annotated with `@RecordUse()`. If there are no /// calls to the definition, either because it was treeshaken, because it was /// not annotated, or because it does not exist, returns `false`. - bool hasNonConstArguments(Identifier method) => - _callTo(method)?.references.any( - (reference) { - final nonConstArguments = reference.arguments?.nonConstArguments; - final hasNamed = nonConstArguments?.named.isNotEmpty ?? false; - final hasPositional = - nonConstArguments?.positional.isNotEmpty ?? false; - return hasNamed || hasPositional; - }, - ) ?? - false; + bool hasNonConstArguments(Identifier identifier) { + return (_recordings.calls[identifier] ?? []).any( + (element) => switch (element) { + CallTearOff() => true, + CallWithArguments call => call.positionalArguments.any( + (argument) => argument == null, + ), + }, + ); + } +} - Usage<CallReference>? _callTo(Identifier definition) => _usages.calls - .firstWhereOrNull((call) => call.definition.identifier == definition); +extension type ConstantInstance(Map<String, Constant> _fields) { + bool hasField(String key) => _fields.containsKey(key); + + Object? operator [](String key) { + if (!hasField(key)) { + throw ArgumentError('No field with name $key found.'); + } + return _fields[key]!.toValue(); + } }
diff --git a/pkg/record_use/lib/src/recordings.dart b/pkg/record_use/lib/src/recordings.dart new file mode 100644 index 0000000..01349e4 --- /dev/null +++ b/pkg/record_use/lib/src/recordings.dart
@@ -0,0 +1,237 @@ +// ignore_for_file: public_member_api_docs, sort_constructors_first +// Copyright (c) 2024, 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 'constant.dart'; +import 'definition.dart'; +import 'helper.dart'; +import 'identifier.dart'; +import 'location.dart' show Location; +import 'metadata.dart'; +import 'reference.dart'; + +/// [Recordings] combines recordings of calls and instances with metadata. +/// +/// This class acts as the top-level container for recorded usage information. +/// The metadata provides context for the recording, such as version and +/// commentary. The [callsForDefinition] and [instancesForDefinition] store the +/// core data, associating each [Definition] with its corresponding [Reference] +/// details. +/// +/// The class uses a normalized JSON format, allowing the reuse of locations and +/// constants across multiple recordings to optimize storage. +class Recordings { + /// [Metadata] such as the recording protocol version. + final Metadata metadata; + + /// The collected [CallReference]s for each [Definition]. + final Map<Definition, List<CallReference>> callsForDefinition; + + late final Map<Identifier, List<CallReference>> calls = callsForDefinition + .map((definition, calls) => MapEntry(definition.identifier, calls)); + + /// The collected [InstanceReference]s for each [Definition]. + final Map<Definition, List<InstanceReference>> instancesForDefinition; + + late final Map<Identifier, List<InstanceReference>> instances = + instancesForDefinition.map( + (definition, instances) => MapEntry(definition.identifier, instances), + ); + + static const _metadataKey = 'metadata'; + static const _constantsKey = 'constants'; + static const _locationsKey = 'locations'; + static const _recordingsKey = 'recordings'; + static const _callsKey = 'calls'; + static const _instancesKey = 'instances'; + static const _definitionKey = 'definition'; + + Recordings({ + required this.metadata, + required this.callsForDefinition, + required this.instancesForDefinition, + }); + + /// Decodes a JSON representation into a [Recordings] object. + /// + /// The format is specifically designed to reduce redundancy and improve + /// efficiency. Identifiers and constants are stored in separate tables, + /// allowing them to be referenced by index in the `recordings` map. + factory Recordings.fromJson(Map<String, Object?> json) { + final constants = <Constant>[]; + for (final constantJsonObj in json[_constantsKey] as List? ?? []) { + final constantJson = constantJsonObj as Map<String, Object?>; + constants.add(Constant.fromJson(constantJson, constants)); + } + final locations = <Location>[]; + for (final locationJsonObj in json[_locationsKey] as List? ?? []) { + final locationJson = locationJsonObj as Map<String, Object?>; + locations.add(Location.fromJson(locationJson)); + } + + final recordings = + (json[_recordingsKey] as List?)?.whereType<Map<String, Object?>>() ?? + []; + final recordedCalls = recordings.where( + (recording) => recording[_callsKey] != null, + ); + final recordedInstances = recordings.where( + (recording) => recording[_instancesKey] != null, + ); + return Recordings( + metadata: Metadata.fromJson(json[_metadataKey] as Map<String, Object?>), + callsForDefinition: { + for (final recording in recordedCalls) + Definition.fromJson( + recording[_definitionKey] as Map<String, Object?>, + ): + (recording[_callsKey] as List) + .map( + (json) => CallReference.fromJson( + json as Map<String, Object?>, + constants, + locations, + ), + ) + .toList(), + }, + instancesForDefinition: { + for (final recording in recordedInstances) + Definition.fromJson( + recording[_definitionKey] as Map<String, Object?>, + ): + (recording[_instancesKey] as List) + .map( + (json) => InstanceReference.fromJson( + json as Map<String, Object?>, + constants, + locations, + ), + ) + .toList(), + }, + ); + } + + /// Encodes this object into a JSON representation. + /// + /// This method normalizes identifiers and constants for storage efficiency. + Map<String, Object?> toJson() { + final constants = + { + ...callsForDefinition.values + .expand((element) => element) + .whereType<CallWithArguments>() + .expand( + (call) => [ + ...call.positionalArguments, + ...call.namedArguments.values, + ], + ) + .nonNulls, + ...instancesForDefinition.values + .expand((element) => element) + .expand( + (instance) => { + ...instance.instanceConstant.fields.values, + instance.instanceConstant, + }, + ), + }.flatten().asMapToIndices; + final locations = + { + ...callsForDefinition.values + .expand((calls) => calls) + .map((call) => call.location), + ...instancesForDefinition.values + .expand((instances) => instances) + .map((instance) => instance.location), + }.asMapToIndices; + return { + _metadataKey: metadata.json, + if (constants.isNotEmpty) + _constantsKey: + constants.keys + .map((constant) => constant.toJson(constants)) + .toList(), + if (locations.isNotEmpty) + _locationsKey: + locations.keys.map((location) => location.toJson()).toList(), + if (callsForDefinition.isNotEmpty || instancesForDefinition.isNotEmpty) + _recordingsKey: [ + if (callsForDefinition.isNotEmpty) + ...callsForDefinition.entries.map( + (entry) => { + _definitionKey: entry.key.toJson(), + _callsKey: + entry.value + .map((call) => call.toJson(constants, locations)) + .toList(), + }, + ), + if (instancesForDefinition.isNotEmpty) + ...instancesForDefinition.entries.map( + (entry) => { + _definitionKey: entry.key.toJson(), + _instancesKey: + entry.value + .map( + (instance) => instance.toJson(constants, locations), + ) + .toList(), + }, + ), + ], + }; + } + + @override + bool operator ==(covariant Recordings other) { + if (identical(this, other)) return true; + + return other.metadata == metadata && + deepEquals(other.callsForDefinition, callsForDefinition) && + deepEquals(other.instancesForDefinition, instancesForDefinition); + } + + @override + int get hashCode => Object.hash( + metadata.hashCode, + deepHash(callsForDefinition), + deepHash(instancesForDefinition), + ); +} + +extension on Iterable<Constant> { + Set<Constant> flatten() { + final constants = <Constant>{}; + for (final constant in this) { + depthFirstSearch(constant, constants); + } + return constants; + } + + void depthFirstSearch(Constant constant, Set<Constant> collected) { + final children = switch (constant) { + ListConstant<Constant>() => constant.value, + MapConstant<Constant>() => constant.value.values, + InstanceConstant() => constant.fields.values, + _ => <Constant>[], + }; + for (final child in children) { + if (!collected.contains(child)) { + depthFirstSearch(child, collected); + } + } + collected.add(constant); + } +} + +extension _PrivateIterableExtension<T> on Iterable<T> { + /// Transform list to map, faster than using list.indexOf + Map<T, int> get asMapToIndices { + var i = 0; + return {for (final element in this) element: i++}; + } +}
diff --git a/pkg/record_use/lib/src/reference.dart b/pkg/record_use/lib/src/reference.dart new file mode 100644 index 0000000..8cb3b96 --- /dev/null +++ b/pkg/record_use/lib/src/reference.dart
@@ -0,0 +1,189 @@ +// Copyright (c) 2024, 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 'constant.dart'; +import 'helper.dart'; +import 'identifier.dart'; +import 'location.dart' show Location; + +const _loadingUnitKey = 'loading_unit'; + +/// A reference to *something*. +/// +/// The something might be a call or an instance, matching a [CallReference] or +/// an [InstanceReference]. +/// All references have in common that they occur in a [loadingUnit], which we +/// record to be able to piece together which loading units are "related", for +/// example all needing the same asset. +sealed class Reference { + final String? loadingUnit; + final Location location; + + const Reference({required this.loadingUnit, required this.location}); + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + + return other is Reference && + other.loadingUnit == loadingUnit && + other.location == location; + } + + @override + int get hashCode => Object.hash(loadingUnit, location); + + Map<String, Object?> toJson( + Map<Constant, int> constants, + Map<Location, int> locations, + ) => {_loadingUnitKey: loadingUnit, _locationKey: locations[location]}; +} + +const _locationKey = '@'; +const _positionalKey = 'positional'; +const _namedKey = 'named'; +const _typeKey = 'type'; + +/// A reference to a call to some [Identifier]. +/// +/// This might be an actual call, in which case we record the arguments, or a +/// tear-off, in which case we can't record the arguments. +sealed class CallReference extends Reference { + const CallReference({required super.loadingUnit, required super.location}); + + static CallReference fromJson( + Map<String, Object?> json, + List<Constant> constants, + List<Location> locations, + ) { + final loadingUnit = json[_loadingUnitKey] as String?; + final location = locations[json[_locationKey] as int]; + return json[_typeKey] == 'tearoff' + ? CallTearOff(loadingUnit: loadingUnit, location: location) + : CallWithArguments( + positionalArguments: + (json[_positionalKey] as List<dynamic>? ?? []) + .whereType<int?>() + .map((index) { + return index != null ? constants[index] : null; + }) + .toList(), + namedArguments: (json[_namedKey] as Map<String, Object?>? ?? {}).map( + (key, value) => + MapEntry(key, value != null ? constants[value as int] : null), + ), + loadingUnit: loadingUnit, + location: location, + ); + } +} + +/// A reference to a call to some [Identifier] with [positionalArguments] and +/// [namedArguments]. +final class CallWithArguments extends CallReference { + final List<Constant?> positionalArguments; + final Map<String, Constant?> namedArguments; + + const CallWithArguments({ + required this.positionalArguments, + required this.namedArguments, + required super.loadingUnit, + required super.location, + }); + + @override + Map<String, Object?> toJson( + Map<Constant, int> constants, + Map<Location, int> locations, + ) { + final positionalJson = + positionalArguments.map((constant) => constants[constant]).toList(); + final namedJson = namedArguments.map( + (name, constant) => MapEntry(name, constants[constant]), + ); + return { + _typeKey: 'with_arguments', + if (positionalJson.isNotEmpty) _positionalKey: positionalJson, + if (namedJson.isNotEmpty) _namedKey: namedJson, + ...super.toJson(constants, locations), + }; + } + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (!(super == other)) return false; + + return other is CallWithArguments && + deepEquals(other.positionalArguments, positionalArguments) && + deepEquals(other.namedArguments, namedArguments); + } + + @override + int get hashCode => Object.hash( + deepHash(positionalArguments), + deepHash(namedArguments), + super.hashCode, + ); +} + +/// A reference to a tear-off use of the [Identifier]. This means that we can't +/// record the arguments possibly passed to the method somewhere else. +final class CallTearOff extends CallReference { + const CallTearOff({required super.loadingUnit, required super.location}); + + @override + Map<String, Object?> toJson( + Map<Constant, int> constants, + Map<Location, int> locations, + ) { + return {_typeKey: 'tearoff', ...super.toJson(constants, locations)}; + } +} + +final class InstanceReference extends Reference { + final InstanceConstant instanceConstant; + + const InstanceReference({ + required this.instanceConstant, + required super.loadingUnit, + required super.location, + }); + + static const _constantKey = 'constant_index'; + + factory InstanceReference.fromJson( + Map<String, Object?> json, + List<Constant> constants, + List<Location> locations, + ) { + return InstanceReference( + instanceConstant: + constants[json[_constantKey] as int] as InstanceConstant, + loadingUnit: json[_loadingUnitKey] as String?, + location: locations[json[_locationKey] as int], + ); + } + + @override + Map<String, Object?> toJson( + Map<Constant, int> constants, + Map<Location, int> locations, + ) => { + _constantKey: constants[instanceConstant]!, + ...super.toJson(constants, locations), + }; + + @override + bool operator ==(Object other) { + if (identical(this, other)) return true; + if (!(super == other)) return false; + + return other is InstanceReference && + other.instanceConstant == instanceConstant; + } + + @override + int get hashCode => Object.hash(instanceConstant, super.hashCode); +}
diff --git a/pkg/record_use/lib/src/signature.dart b/pkg/record_use/lib/src/signature.dart new file mode 100644 index 0000000..c89c740 --- /dev/null +++ b/pkg/record_use/lib/src/signature.dart
@@ -0,0 +1,218 @@ +// Copyright (c) 2025, 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:collection/collection.dart'; + +import '../record_use_internal.dart' show CallWithArguments; +import 'constant.dart'; +import 'helper.dart'; // Assuming helper.dart contains the deepEquals function + +/// Represents the signature of a Dart method, categorizing its parameters. +class Signature { + /// List of required positional parameter names. + final List<String> positionalParameters; + + /// List of optional positional parameter names, enclosed in `[]`. + final List<String> positionalOptionalParameters; + + /// List of required named parameter names, preceded by `required`. + final List<String> namedParameters; + + /// List of optional named parameter names, enclosed in `{}`. + final List<String> namedOptionalParameters; + + /// Creates a new [Signature] instance. + const Signature({ + required this.positionalParameters, + required this.positionalOptionalParameters, + required this.namedParameters, + required this.namedOptionalParameters, + }); + + ({List<Constant?> positional, Map<String, Constant?> named}) parseArguments( + CallWithArguments call, + ) { + final positionalArguments = <Constant?>[]; + final namedArguments = <String, Constant?>{}; + final names = [ + ...positionalParameters, + ...positionalOptionalParameters, + ...namedParameters, + ...namedOptionalParameters, + ]; + if (call.positionalArguments.length != names.length) { + throw FormatException( + ''' +Invalid number of arguments - $names vs ${call.positionalArguments} and ${call.namedArguments}''', + ); + } + final sortedNames = names.sorted(); + final mapping = <String, Constant?>{}; + for (var i = 0; i < sortedNames.length; i++) { + final name = sortedNames[i]; + mapping[name] = call.namedArguments[name] ?? call.positionalArguments[i]; + } + for (var name in names) { + var constant = mapping[name]; + if (positionalParameters.contains(name) || + positionalOptionalParameters.contains(name)) { + positionalArguments.add(constant); + } else if (namedParameters.contains(name) || + namedOptionalParameters.contains(name)) { + namedArguments[name] = constant; + } + } + return (named: namedArguments, positional: positionalArguments); + } + + /// Parses a Dart method signature string and returns a [Signature] instance. + /// + /// The signature string should follow the standard Dart method signature + /// syntax, including return type, method name, and parameter list enclosed in + /// parentheses. This parser attempts to correctly identify positional, + /// optional positional, required named, and optional named parameters, + /// extracting only their names. + /// It handles basic type annotations and default values but might not cover + /// all edge cases of complex Dart type syntax. + /// + /// Example: + /// ```dart + /// final signatureString = '''String greet(String name, + /// [String? greeting = "Hello"])'''; + /// final signature = Signature.parseMethodSignature(signatureString); + /// print(signature.positionalParameters); // Output: [name] + /// print(signature.positionalOptionalParameters); // Output: [greeting] + /// print(signature.namedParameters); // Output: [] + /// print(signature.namedOptionalParameters); // Output: [] + /// ``` + /// + /// Throws a [FormatException] if the provided [signature] string does not + /// match the expected basic method signature format. + factory Signature.parseMethodSignature(String signature) { + var firstParensIndex = signature.indexOf('('); + int? lastParensIndex = signature.lastIndexOf(')'); + if (firstParensIndex == -1 || lastParensIndex == -1) { + throw const FormatException('Invalid signature format'); + } + final parameterString = signature + .substring(firstParensIndex + 1, lastParensIndex) + .split('\n') + .map((line) => line.trim()) + .whereNot((line) => line.startsWith('//')) + .join('\n'); + + final positionalParams = <String>[]; + final positionalOptionalParams = <String>[]; + final namedParams = <String>[]; + final namedOptionalParams = <String>[]; + + if (parameterString.isNotEmpty) { + var inOptionalPositional = false; + var inNamed = false; + + var i = 0; + while (i < parameterString.length) { + var start = i; + var bracketCounter = 0; + for (; i < parameterString.length; i++) { + if (parameterString[i] == '<') { + bracketCounter++; + } else if (parameterString[i] == '>') { + bracketCounter--; + } else if (parameterString[i] == ',' && bracketCounter == 0) { + break; + } + } + var param = parameterString.substring(start, i); + i++; + + param = param.trim(); + if (param.isEmpty) { + continue; + } + + if (param.startsWith('[')) { + inOptionalPositional = true; + param = param.substring(1).trim(); + } else if (param.startsWith('{')) { + inNamed = true; + param = param.substring(1).trim(); + } + if (param.endsWith(']')) { + param = param.substring(0, param.length - 1).trim(); + } else if (param.endsWith('}')) { + param = param.substring(0, param.length - 1).trim(); + } + + if (inOptionalPositional) { + positionalOptionalParams.add(_extractParameterName(param)); + } else if (inNamed) { + var req = 'required '; + if (param.startsWith(req)) { + namedParams.add(_extractParameterName(param.substring(req.length))); + } else { + namedOptionalParams.add(_extractParameterName(param)); + } + } else { + positionalParams.add(_extractParameterName(param)); + } + } + } + + // Extract only the name for positional parameters + final positionalNames = + positionalParams.map(_extractParameterName).toList(); + final positionalOptionalNames = + positionalOptionalParams.map(_extractParameterName).toList(); + + return Signature( + positionalParameters: positionalNames, + positionalOptionalParameters: positionalOptionalNames, + namedParameters: namedParams, + namedOptionalParameters: namedOptionalParams, + ); + } + + /// Extracts the parameter name from a parameter declaration string. + /// + /// This method splits the declaration by the `=` sign to remove default + /// values and then by spaces, taking the last part as the parameter name. + /// This is a simple heuristic and might not work perfectly for all complex + /// type annotations. + static String _extractParameterName(String parameterDeclaration) { + return parameterDeclaration.split('=').first.trim().split(' ').last; + } + + @override + bool operator ==(Object other) => + identical(this, other) || + other is Signature && + runtimeType == other.runtimeType && + deepEquals(positionalParameters, other.positionalParameters) && + deepEquals( + positionalOptionalParameters, + other.positionalOptionalParameters, + ) && + deepEquals(namedParameters, other.namedParameters) && + deepEquals(namedOptionalParameters, other.namedOptionalParameters); + + @override + int get hashCode => Object.hash( + positionalParameters.hashCode, + positionalOptionalParameters.hashCode, + namedParameters.hashCode, + namedOptionalParameters.hashCode, + ); + + @override + String toString() { + return ''' +Signature( + positionalParameters: $positionalParameters, + positionalOptionalParameters: $positionalOptionalParameters, + namedParameters: $namedParameters, + namedOptionalParameters: $namedOptionalParameters +)'''; + } +}
diff --git a/pkg/record_use/pubspec.yaml b/pkg/record_use/pubspec.yaml index da8e87a..20fe1b9 100644 --- a/pkg/record_use/pubspec.yaml +++ b/pkg/record_use/pubspec.yaml
@@ -1,11 +1,11 @@ name: record_use description: > The serialization logic and API for the usage recording SDK feature. -version: 0.3.1-wip +version: 0.4.0 repository: https://github.com/dart-lang/sdk/tree/main/pkg/record_use environment: - sdk: ^3.5.0 + sdk: ^3.7.0 resolution: workspace
diff --git a/pkg/record_use/test/signature_test.dart b/pkg/record_use/test/signature_test.dart new file mode 100644 index 0000000..563368d --- /dev/null +++ b/pkg/record_use/test/signature_test.dart
@@ -0,0 +1,147 @@ +// Copyright (c) 2025, 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:record_use/src/signature.dart'; +import 'package:test/test.dart'; + +void main() { + group('Signature.parseMethodSignature', () { + test('positional and optional positional parameters', () { + final signature = + 'String greet(String name, [String? greeting = "Hello"])'; + final expected = const Signature( + positionalParameters: ['name'], + positionalOptionalParameters: ['greeting'], + namedParameters: [], + namedOptionalParameters: [], + ); + expect(Signature.parseMethodSignature(signature), expected); + }); + + test('only named parameters (required and optional)', () { + final signature = + 'void process({required int id, String? label, double value = 0.0})'; + final expected = const Signature( + positionalParameters: [], + positionalOptionalParameters: [], + namedParameters: ['id'], + namedOptionalParameters: ['label', 'value'], + ); + expect(Signature.parseMethodSignature(signature), expected); + }); + + test( + 'positional and optional positional parameters (without default values)', + () { + final signature = ''' +Future<void> fetchData(String url, int retries, [bool? cache, Duration? timeout])'''; + final expected = const Signature( + positionalParameters: ['url', 'retries'], + positionalOptionalParameters: ['cache', 'timeout'], + namedParameters: [], + namedOptionalParameters: [], + ); + expect(Signature.parseMethodSignature(signature), expected); + }, + ); + + test('positional and named parameters (with default values)', () { + final signature = + 'void log(String message, {int? level = 0, DateTime? timestamp})'; + final expected = const Signature( + positionalParameters: ['message'], + positionalOptionalParameters: [], + namedParameters: [], + namedOptionalParameters: ['level', 'timestamp'], + ); + expect(Signature.parseMethodSignature(signature), expected); + }); + + test('only positional parameters', () { + final signature = 'int add(int a, int b)'; + final expected = const Signature( + positionalParameters: ['a', 'b'], + positionalOptionalParameters: [], + namedParameters: [], + namedOptionalParameters: [], + ); + expect(Signature.parseMethodSignature(signature), expected); + }); + + test('only optional positional parameters', () { + final signature = 'String format([String? prefix, String? suffix])'; + final expected = const Signature( + positionalParameters: [], + positionalOptionalParameters: ['prefix', 'suffix'], + namedParameters: [], + namedOptionalParameters: [], + ); + expect(Signature.parseMethodSignature(signature), expected); + }); + + test('only required named parameters', () { + final signature = + 'void config({required String apiKey, required String apiUrl})'; + final expected = const Signature( + positionalParameters: [], + positionalOptionalParameters: [], + namedParameters: ['apiKey', 'apiUrl'], + namedOptionalParameters: [], + ); + expect(Signature.parseMethodSignature(signature), expected); + }); + + test('handles signatures with no parameters', () { + final signature = 'void doSomething()'; + final expected = const Signature( + positionalParameters: [], + positionalOptionalParameters: [], + namedParameters: [], + namedOptionalParameters: [], + ); + expect(Signature.parseMethodSignature(signature), expected); + }); + + test('handles signatures with complex type annotations', () { + final signature = ''' +List<Map<String, int>> processData(Map<String, List<int>> input, [Set<String>? filter])'''; + final expected = const Signature( + positionalParameters: ['input'], + positionalOptionalParameters: ['filter'], + namedParameters: [], + namedOptionalParameters: [], + ); + expect(Signature.parseMethodSignature(signature), expected); + }); + + test('handles signatures with complex type annotations', () { + final signature = ''' +void test(Object? description, dynamic Function() body, + {String? testOn, + Timeout? timeout, + Object? skip, + Object? tags, + Map<String, Object?>? onPlatform, + int? retry, + // TODO(https://github.com/dart-lang/test/issues/2205): Remove deprecated. + // Map<String, Object?>? error, + @Deprecated('Debug only') @doNotSubmit bool solo = false})'''; + final expected = const Signature( + positionalParameters: ['description', 'body'], + positionalOptionalParameters: [], + namedParameters: [], + namedOptionalParameters: [ + 'testOn', + 'timeout', + 'skip', + 'tags', + 'onPlatform', + 'retry', + 'solo', + ], + ); + expect(Signature.parseMethodSignature(signature), expected); + }); + }); +}
diff --git a/pkg/record_use/test/storage_test.dart b/pkg/record_use/test/storage_test.dart index 7a8da25..d62610d 100644 --- a/pkg/record_use/test/storage_test.dart +++ b/pkg/record_use/test/storage_test.dart
@@ -10,22 +10,33 @@ import 'test_data.dart'; void main() { - final json = jsonDecode(recordedUsesJson) as Map<String, dynamic>; - test( - 'JSON', - () => expect(recordedUses.toJson(), json), - ); + group('object 1', () { + final json = jsonDecode(recordedUsesJson) as Map<String, Object?>; + test('JSON', () => expect(recordedUses.toJson(), json)); - test( - 'Object', - () => expect(UsageRecord.fromJson(json), recordedUses), - ); + test('Object', () => expect(Recordings.fromJson(json), recordedUses)); - test('Json->Object->Json', () { - expect(UsageRecord.fromJson(json).toJson(), json); + test('Json->Object->Json', () { + expect(Recordings.fromJson(json).toJson(), json); + }); + + test('Object->Json->Object', () { + expect(Recordings.fromJson(recordedUses.toJson()), recordedUses); + }); }); - test('Object->Json->Object', () { - expect(UsageRecord.fromJson(recordedUses.toJson()), recordedUses); + group('object 2', () { + final json2 = jsonDecode(recordedUsesJson2) as Map<String, Object?>; + test('JSON', () => expect(recordedUses2.toJson(), json2)); + + test('Object', () => expect(Recordings.fromJson(json2), recordedUses2)); + + test('Json->Object->Json', () { + expect(Recordings.fromJson(json2).toJson(), json2); + }); + + test('Object->Json->Object', () { + expect(Recordings.fromJson(recordedUses2.toJson()), recordedUses2); + }); }); }
diff --git a/pkg/record_use/test/test_data.dart b/pkg/record_use/test/test_data.dart index d758481..c1aae17 100644 --- a/pkg/record_use/test/test_data.dart +++ b/pkg/record_use/test/test_data.dart
@@ -6,218 +6,243 @@ import 'package:record_use/record_use_internal.dart'; final callId = Identifier( - importUri: Uri.parse('file://lib/_internal/js_runtime/lib/js_helper.dart') - .toString(), - parent: 'MyClass', + importUri: + Uri.parse( + 'file://lib/_internal/js_runtime/lib/js_helper.dart', + ).toString(), + scope: 'MyClass', name: 'get:loadDeferredLibrary', ); final instanceId = Identifier( - importUri: Uri.parse('file://lib/_internal/js_runtime/lib/js_helper.dart') - .toString(), + importUri: + Uri.parse( + 'file://lib/_internal/js_runtime/lib/js_helper.dart', + ).toString(), name: 'MyAnnotation', ); -final recordedUses = UsageRecord( - metadata: Metadata( - version: Version(1, 6, 2, pre: 'wip', build: '5.-.2.z'), - comment: - 'Recorded references at compile time and their argument values, as far' - ' as known, to definitions annotated with @RecordUse', - ), - instances: [ - Usage( - definition: Definition( - identifier: instanceId, - location: Location( - uri: Uri.parse('file://lib/_internal/js_runtime/lib/js_helper.dart') - .toString(), - line: 15, - column: 30, - ), +final recordedUses = Recordings( + metadata: Metadata.fromJson({ + 'version': Version(1, 6, 2, pre: 'wip', build: '5.-.2.z').toString(), + 'comment': + 'Recorded references at compile time and their argument values, as' + ' far as known, to definitions annotated with @RecordUse', + }), + callsForDefinition: { + Definition(identifier: callId, loadingUnit: 'part_15.js'): [ + const CallWithArguments( + positionalArguments: [ + BoolConstant(false), + StringConstant('mercury'), + IntConstant(1), + StringConstant('jenkins'), + StringConstant('lib_SHA1'), + ], + namedArguments: {}, + loadingUnit: 'o.js', + location: Location(uri: 'lib/test.dart'), ), - references: [ - InstanceReference( - instanceConstant: const InstanceConstant( - fields: { - 'a': IntConstant(42), - 'b': NullConstant(), - }, - ), - location: Location( - uri: Uri.parse('file://lib/_internal/js_runtime/lib/js_helper.dart') - .toString(), - line: 40, - column: 30, - ), - loadingUnit: '3', - ), - ], - ), - ], - calls: [ - Usage( - definition: Definition( - identifier: callId, - location: Location( - uri: Uri.parse('file://lib/_internal/js_runtime/lib/js_helper.dart') - .toString(), - line: 12, - column: 67, - ), - loadingUnit: 'part_15.js', + const CallWithArguments( + positionalArguments: [ + StringConstant('lib_SHA1'), + IntConstant(0), + MapConstant<IntConstant>({'key': IntConstant(99)}), + StringConstant('jenkins'), + ListConstant([ + StringConstant('camus'), + ListConstant([ + StringConstant('einstein'), + StringConstant('insert'), + BoolConstant(false), + ]), + StringConstant('einstein'), + ]), + ], + namedArguments: {}, + loadingUnit: 'o.js', + location: Location(uri: 'lib/test2.dart'), ), - references: [ - CallReference( - arguments: const Arguments( - constArguments: ConstArguments( - positional: { - 0: StringConstant('lib_SHA1'), - 1: BoolConstant(false), - 2: IntConstant(1) - }, - named: { - 'leroy': StringConstant('jenkins'), - 'freddy': StringConstant('mercury') - }, - ), - ), - location: Location( - uri: Uri.parse( - 'file://benchmarks/OmnibusDeferred/dart/OmnibusDeferred.dart') - .toString(), - line: 14, - column: 49, - ), - loadingUnit: 'o.js', + ], + }, + instancesForDefinition: { + Definition(identifier: instanceId): [ + const InstanceReference( + instanceConstant: InstanceConstant( + fields: {'a': IntConstant(42), 'b': NullConstant()}, ), - CallReference( - arguments: const Arguments( - constArguments: ConstArguments( - positional: { - 0: StringConstant('lib_SHA1'), - 2: IntConstant(0), - 4: MapConstant<IntConstant>({'key': IntConstant(99)}), - }, - named: { - 'leroy': StringConstant('jenkins'), - 'albert': ListConstant([ - StringConstant('camus'), - ListConstant([ - StringConstant('einstein'), - StringConstant('insert'), - BoolConstant(false), - ]), - StringConstant('einstein'), - ]), - }, - ), - nonConstArguments: NonConstArguments( - positional: [1], - named: ['freddy'], - ), - ), - location: Location( - uri: Uri.parse( - 'file://benchmarks/OmnibusDeferred/dart/OmnibusDeferred.dart') - .toString(), - line: 14, - column: 48, - ), - loadingUnit: 'o.js', - ), - ], - ), - ], + loadingUnit: '3', + location: Location(uri: 'lib/test3.dart'), + ), + ], + }, +); + +final recordedUses2 = Recordings( + metadata: Metadata.fromJson({ + 'version': Version(1, 6, 2, pre: 'wip', build: '5.-.2.z').toString(), + 'comment': + 'Recorded references at compile time and their argument values, as' + ' far as known, to definitions annotated with @RecordUse', + }), + callsForDefinition: { + Definition(identifier: callId, loadingUnit: 'part_15.js'): [ + const CallWithArguments( + positionalArguments: [BoolConstant(false), IntConstant(1)], + namedArguments: { + 'freddy': StringConstant('mercury'), + 'answer': IntConstant(42), + }, + loadingUnit: 'o.js', + location: Location(uri: 'lib/test3.dart'), + ), + ], + }, + instancesForDefinition: {}, ); final recordedUsesJson = '''{ "metadata": { - "comment": - "Recorded references at compile time and their argument values, as far as known, to definitions annotated with @RecordUse", - "version": "1.6.2-wip+5.-.2.z" + "version": "1.6.2-wip+5.-.2.z", + "comment": "Recorded references at compile time and their argument values, as far as known, to definitions annotated with @RecordUse" }, - "uris": [ - "file://lib/_internal/js_runtime/lib/js_helper.dart", - "file://benchmarks/OmnibusDeferred/dart/OmnibusDeferred.dart" - ], - "ids": [ - {"uri": 0, "parent": "MyClass", "name": "get:loadDeferredLibrary"}, - {"uri": 0, "name": "MyAnnotation"} - ], "constants": [ - {"type": "String", "value": "jenkins"}, - {"type": "String", "value": "mercury"}, - {"type": "String", "value": "lib_SHA1"}, - {"type": "bool", "value": false}, - {"type": "int", "value": 1}, - {"type": "String", "value": "camus"}, - {"type": "String", "value": "einstein"}, - {"type": "String", "value": "insert"}, { - "type": "list", - "value": [6, 7, 3] + "type": "bool", + "value": false }, { - "type": "list", - "value": [5, 8, 6] + "type": "String", + "value": "mercury" }, - {"type": "int", "value": 0}, - {"type": "int", "value": 99}, + { + "type": "int", + "value": 1 + }, + { + "type": "String", + "value": "jenkins" + }, + { + "type": "String", + "value": "lib_SHA1" + }, + { + "type": "int", + "value": 0 + }, + { + "type": "int", + "value": 99 + }, { "type": "map", - "value": {"key": 11} + "value": { + "key": 6 + } }, - {"type": "int", "value": 42}, - {"type": "Null"}, - {"type": "Instance", "value": {"a": 13, "b": 14}} - ], - "calls": [ { - "definition": { - "id": 0, - "@": {"uri": 0, "line": 12, "column": 67}, - "loadingUnit": "part_15.js" - }, - "references": [ - { - "arguments": { - "const": { - "positional": {"0": 2, "1": 3, "2": 4}, - "named": {"leroy": 0, "freddy": 1} - } - }, - "loadingUnit": "o.js", - "@": {"uri": 1, "line": 14, "column": 49} - }, - { - "arguments": { - "const": { - "positional": {"0": 2, "2": 10, "4": 12}, - "named": {"leroy": 0, "albert": 9} - }, - "nonConst": { - "positional": [1], - "named": ["freddy"] - } - }, - "loadingUnit": "o.js", - "@": {"uri": 1, "line": 14, "column": 48} - } + "type": "String", + "value": "camus" + }, + { + "type": "String", + "value": "einstein" + }, + { + "type": "String", + "value": "insert" + }, + { + "type": "list", + "value": [ + 9, + 10, + 0 ] + }, + { + "type": "list", + "value": [ + 8, + 11, + 9 + ] + }, + { + "type": "int", + "value": 42 + }, + { + "type": "Null" + }, + { + "type": "Instance", + "value": { + "a": 13, + "b": 14 + } } ], - "instances": [ + "locations": [ + { + "uri": "lib/test.dart" + }, + { + "uri": "lib/test2.dart" + }, + { + "uri": "lib/test3.dart" + } + ], + "recordings": [ { "definition": { - "id": 1, - "@": {"uri": 0, "line": 15, "column": 30}, - "loadingUnit": null + "identifier": { + "uri": "file://lib/_internal/js_runtime/lib/js_helper.dart", + "scope": "MyClass", + "name": "get:loadDeferredLibrary" + }, + "loading_unit": "part_15.js" }, - "references": [ + "calls": [ { - "instanceConstant": 15, - "loadingUnit": "3", - "@": {"uri": 0, "line": 40, "column": 30} + "type": "with_arguments", + "positional": [ + 0, + 1, + 2, + 3, + 4 + ], + "loading_unit": "o.js", + "@": 0 + }, + { + "type": "with_arguments", + "positional": [ + 4, + 5, + 7, + 3, + 12 + ], + "loading_unit": "o.js", + "@": 1 + } + ] + }, + { + "definition": { + "identifier": { + "uri": "file://lib/_internal/js_runtime/lib/js_helper.dart", + "name": "MyAnnotation" + } + }, + "instances": [ + { + "constant_index": 15, + "loading_unit": "3", + "@": 2 } ] } @@ -226,51 +251,55 @@ final recordedUsesJson2 = '''{ "metadata": { - "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "1.6.2-wip+5.-.2.z", + "comment": "Recorded references at compile time and their argument values, as far as known, to definitions annotated with @RecordUse" }, - "uris": [ - "package:drop_dylib_recording/src/drop_dylib_recording.dart", - "drop_dylib_recording_calls.dart" - ], - "ids": [ - { - "uri": 0, - "name": "getMathMethod" - } - ], "constants": [ { + "type": "bool", + "value": false + }, + { + "type": "int", + "value": 1 + }, + { "type": "String", - "value": "add" + "value": "mercury" + }, + { + "type": "int", + "value": 42 } ], - "calls": [ + "locations": [ + { + "uri": "lib/test3.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 10, - "column": 6 + "identifier": { + "uri": "file://lib/_internal/js_runtime/lib/js_helper.dart", + "scope": "MyClass", + "name": "get:loadDeferredLibrary" }, - "loadingUnit": "1" + "loading_unit": "part_15.js" }, - "references": [ + "calls": [ { - "arguments": { - "const": { - "positional": { - "0": 0 - } - } + "type": "with_arguments", + "positional": [ + 0, + 1 + ], + "named": { + "freddy": 2, + "answer": 3 }, - "loadingUnit": "1", - "@": { - "uri": 1, - "line": 8, - "column": 3 - } + "loading_unit": "o.js", + "@": 0 } ] }
diff --git a/pkg/record_use/test/usage_test.dart b/pkg/record_use/test/usage_test.dart index bd2e066..f749932 100644 --- a/pkg/record_use/test/usage_test.dart +++ b/pkg/record_use/test/usage_test.dart
@@ -13,97 +13,115 @@ test('All API calls', () { expect( RecordedUsages.fromJson( - jsonDecode(recordedUsesJson) as Map<String, dynamic>) - .argumentsTo(callId), - recordedUses.calls.expand((e) => e.references).map((e) => e.arguments), + jsonDecode(recordedUsesJson) as Map<String, Object?>, + ).constArgumentsFor( + Identifier( + importUri: + Uri.parse( + 'file://lib/_internal/js_runtime/lib/js_helper.dart', + ).toString(), + scope: 'MyClass', + name: 'get:loadDeferredLibrary', + ), + ''' +void loadDeferredLibrary(String s, bool b, int i, {required String singer, String? character})''', + ).length, + 2, ); }); test('All API instances', () { - final references = - recordedUses.instances.expand((instance) => instance.references); - final instances = RecordedUsages.fromJson( - jsonDecode(recordedUsesJson) as Map<String, dynamic>) - .instancesOf(instanceId); - expect(instances, references); + final instance = + RecordedUsages.fromJson( + jsonDecode(recordedUsesJson) as Map<String, Object?>, + ) + .constantsOf( + Identifier( + importUri: + Uri.parse( + 'file://lib/_internal/js_runtime/lib/js_helper.dart', + ).toString(), + name: 'MyAnnotation', + ), + ) + .first; + final instanceMap = + recordedUses.instancesForDefinition.values + .expand((usage) => usage) + .map( + (instance) => instance.instanceConstant.fields.map( + (key, constant) => MapEntry(key, constant.toValue()), + ), + ) + .first; + for (final entry in instanceMap.entries) { + expect(instance[entry.key], entry.value); + } }); test('Specific API calls', () { - final callId = Identifier( - importUri: Uri.parse('file://lib/_internal/js_runtime/lib/js_helper.dart') - .toString(), - parent: 'MyClass', - name: 'get:loadDeferredLibrary', - ); - final arguments = RecordedUsages.fromJson( - jsonDecode(recordedUsesJson) as Map<String, dynamic>) - .argumentsTo(callId)! - .toList(); - expect( - arguments[0].constArguments.named, - const { - 'leroy': StringConstant('jenkins'), - 'freddy': StringConstant('mercury'), - }, - ); - expect( - arguments[0].constArguments.positional, - const { - 0: StringConstant('lib_SHA1'), - 1: BoolConstant(false), - 2: IntConstant(1) - }, - ); - expect(arguments[1].constArguments.named, const { - 'leroy': StringConstant('jenkins'), - 'albert': ListConstant([ - StringConstant('camus'), - ListConstant([ - StringConstant('einstein'), - StringConstant('insert'), - BoolConstant(false), - ]), - StringConstant('einstein'), - ]), - }); - expect(arguments[1].constArguments.positional, const { - 0: StringConstant('lib_SHA1'), - 2: IntConstant(0), - 4: MapConstant({'key': IntConstant(99)}) - }); + var arguments = + RecordedUsages.fromJson( + jsonDecode(recordedUsesJson) as Map<String, Object?>, + ).constArgumentsFor( + Identifier( + importUri: + Uri.parse( + 'file://lib/_internal/js_runtime/lib/js_helper.dart', + ).toString(), + scope: 'MyClass', + name: 'get:loadDeferredLibrary', + ), + ''' +void loadDeferredLibrary(String s, bool b, int i, {required String freddy, String? leroy})''', + ).toList(); + var (named: named0, positional: positional0) = arguments[0]; + expect(named0, const {'freddy': 'mercury', 'leroy': 'jenkins'}); + expect(positional0, const ['lib_SHA1', false, 1]); + var (named: named1, positional: positional1) = arguments[1]; + expect(named1, const {'freddy': 0, 'leroy': 'jenkins'}); + expect(positional1, const [ + [ + 'camus', + ['einstein', 'insert', false], + 'einstein', + ], + 'lib_SHA1', + {'key': 99}, + ]); }); test('Specific API instances', () { - final instanceId = Identifier( - importUri: Uri.parse('file://lib/_internal/js_runtime/lib/js_helper.dart') - .toString(), - name: 'MyAnnotation', - ); - expect( - RecordedUsages.fromJson( - jsonDecode(recordedUsesJson) as Map<String, dynamic>) - .instancesOf(instanceId) - ?.first, - InstanceReference( - instanceConstant: const InstanceConstant( - fields: {'a': IntConstant(42), 'b': NullConstant()}, - ), - location: Location(uri: instanceId.importUri, line: 40, column: 30), - loadingUnit: 3.toString(), - ), - ); + final instance = + RecordedUsages.fromJson( + jsonDecode(recordedUsesJson) as Map<String, Object?>, + ) + .constantsOf( + Identifier( + importUri: + Uri.parse( + 'file://lib/_internal/js_runtime/lib/js_helper.dart', + ).toString(), + name: 'MyAnnotation', + ), + ) + .first; + expect(instance['a'], 42); + expect(instance['b'], null); }); test('HasNonConstInstance', () { - final id = const Identifier( - importUri: 'package:drop_dylib_recording/src/drop_dylib_recording.dart', - name: 'getMathMethod', - ); - expect( - RecordedUsages.fromJson( - jsonDecode(recordedUsesJson2) as Map<String, dynamic>) - .hasNonConstArguments(id), - false); + RecordedUsages.fromJson( + jsonDecode(recordedUsesJson2) as Map<String, Object?>, + ).hasNonConstArguments( + const Identifier( + importUri: + 'package:drop_dylib_recording/src/drop_dylib_recording.dart', + name: 'getMathMethod', + ), + ), + false, + ); }); }
diff --git a/pkg/record_use/test_data/drop_dylib_recording/hook/build.dart b/pkg/record_use/test_data/drop_dylib_recording/hook/build.dart index cfbc206..20c3924 100644 --- a/pkg/record_use/test_data/drop_dylib_recording/hook/build.dart +++ b/pkg/record_use/test_data/drop_dylib_recording/hook/build.dart
@@ -13,8 +13,7 @@ ..onRecord.listen((record) { print('${record.level.name}: ${record.time}: ${record.message}'); }); - final routing = - input.config.linkingEnabled + final routing = input.config.linkingEnabled ? [ToLinkHook(input.packageName)] : const [ToAppBundle()]; await CBuilder.library(
diff --git a/pkg/record_use/test_data/drop_dylib_recording/hook/link.dart b/pkg/record_use/test_data/drop_dylib_recording/hook/link.dart index 8f3dbc2..7336470 100644 --- a/pkg/record_use/test_data/drop_dylib_recording/hook/link.dart +++ b/pkg/record_use/test_data/drop_dylib_recording/hook/link.dart
@@ -8,30 +8,14 @@ import 'package:native_assets_cli/code_assets.dart'; import 'package:record_use/record_use.dart'; -final callIdAdd = const Identifier( - importUri: 'package:drop_dylib_recording/src/drop_dylib_recording.dart', - parent: 'MyMath', - name: 'add', -); - -final callIdMultiply = const Identifier( - importUri: 'package:drop_dylib_recording/src/drop_dylib_recording.dart', - parent: 'MyMath', - name: 'multiply', -); - -final instanceId = const Identifier( - importUri: 'package:drop_dylib_recording/src/drop_dylib_recording.dart', - name: 'RecordCallToC', -); - void main(List<String> arguments) async { await link(arguments, (input, output) async { - final file = File.fromUri(input.recordedUsagesFile!); - final string = await file.readAsString(); - final usages = - RecordedUsages.fromJson(jsonDecode(string) as Map<String, dynamic>); - + final recordedUsagesFile = input.recordedUsagesFile; + if (recordedUsagesFile == null) { + throw ArgumentError( + 'Enable the --enable-experiments=record-use experiment to use this app.'); + } + final usages = await recordedUsages(recordedUsagesFile); final codeAssets = input.assets.code; print('Received assets: ${codeAssets.map((a) => a.id).join(', ')}.'); @@ -42,26 +26,31 @@ final dataLines = <String>[]; // Tree-shake unused assets using calls - for (var callId in [callIdAdd, callIdMultiply]) { - var arguments = usages.argumentsTo(callId); - if (arguments?.isNotEmpty ?? false) { - final argument = - (arguments!.first.constArguments.positional[0] as IntConstant) - .value; - dataLines.add('Argument to "${callId.name}": $argument'); - symbols.add(callId.name); + for (final methodName in ['add', 'multiply']) { + final calls = usages.constArgumentsFor( + Identifier( + importUri: + 'package:drop_dylib_recording/src/drop_dylib_recording.dart', + scope: 'MyMath', + name: methodName, + ), + 'int add(int a, int b)'); + for (var call in calls) { + dataLines.add( + 'A call was made to "$methodName" with the arguments (${call.positional[0] as int},${call.positional[1] as int})'); + symbols.add(methodName); } } argumentsFile.writeAsStringSync(dataLines.join('\n')); // Tree-shake unused assets - final instances = usages.instancesOf(instanceId) ?? []; + final instances = usages.constantsOf(Identifier( + importUri: 'package:drop_dylib_recording/src/drop_dylib_recording.dart', + name: 'RecordCallToC', + )); for (final instance in instances) { - final symbol = - (instance.instanceConstant.fields.values.first as StringConstant) - .value; - + final symbol = instance['symbol'] as String; symbols.add(symbol); } @@ -73,6 +62,14 @@ print('Keeping only ${neededCodeAssets.map((e) => e.id).join(', ')}.'); output.assets.code.addAll(neededCodeAssets); - output.addDependency(input.packageRoot.resolve('hook/link.dart')); + output.addDependency(recordedUsagesFile); }); } + +Future<RecordedUsages> recordedUsages(Uri recordedUsagesFile) async { + final file = File.fromUri(recordedUsagesFile); + final string = await file.readAsString(); + final usages = + RecordedUsages.fromJson(jsonDecode(string) as Map<String, Object?>); + return usages; +}
diff --git a/pkg/vm/lib/transformations/record_use/constant_collector.dart b/pkg/vm/lib/transformations/record_use/constant_collector.dart index e204ed1..a1d77fab 100644 --- a/pkg/vm/lib/transformations/record_use/constant_collector.dart +++ b/pkg/vm/lib/transformations/record_use/constant_collector.dart
@@ -79,8 +79,9 @@ void visitInstanceConstant(InstanceConstant constant) { assert(_expression != null); final classNode = constant.classNode; - if (_hasRecordUseAnnotation[classNode] ??= - recordUse.findRecordUseAnnotation(classNode).isNotEmpty) { + if (_hasRecordUseAnnotation[classNode] ??= recordUse.hasRecordUseAnnotation( + classNode, + )) { collector(_expression!, constant); } for (final value in constant.fieldValues.values) {
diff --git a/pkg/vm/lib/transformations/record_use/record_call.dart b/pkg/vm/lib/transformations/record_use/record_call.dart index d2e8959..8452252 100644 --- a/pkg/vm/lib/transformations/record_use/record_call.dart +++ b/pkg/vm/lib/transformations/record_use/record_call.dart
@@ -2,7 +2,6 @@ // 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:collection/collection.dart'; import 'package:front_end/src/kernel/record_use.dart' as recordUse; import 'package:kernel/ast.dart' as ast; import 'package:record_use/record_use_internal.dart'; @@ -13,14 +12,15 @@ /// * static or top-level method calls through [recordStaticInvocation] /// * tear-offs through [recordConstantExpression] /// -/// The result of adding calls can be fetched from [foundCalls]. +/// The result of adding calls can be fetched from [callsForMethod]. class CallRecorder { - /// The collection of recorded calls found so far. - Iterable<Usage<CallReference>> get foundCalls => _callsForMethod.values; + /// Keep track of the calls which are recorded, to easily add newly found + /// ones. + final Map<Identifier, List<CallReference>> callsForMethod = {}; /// Keep track of the calls which are recorded, to easily add newly found /// ones. - final Map<ast.Procedure, Usage<CallReference>> _callsForMethod = {}; + final Map<Identifier, String> loadingUnitForDefinition = {}; /// The ordered list of loading units to retrieve the loading unit index from. final List<LoadingUnit> _loadingUnits; @@ -28,16 +28,18 @@ /// The source uri to base relative URIs off of. final Uri _source; + /// Whether to save line and column info as well as the URI. + //TODO(mosum): add verbose mode to enable this + bool exactLocation = false; + CallRecorder(this._source, this._loadingUnits); /// Will record a static invocation if it is annotated with `@RecordUse`. void recordStaticInvocation(ast.StaticInvocation node) { - final annotations = recordUse.findRecordUseAnnotation(node.target); - if (annotations.isNotEmpty) { - final call = _getCall(node.target); - + if (recordUse.hasRecordUseAnnotation(node.target)) { // Collect the (int, bool, double, or String) arguments passed in the call. - call.references.add(_createCallReference(node)); + final createCallReference = _createCallReference(node); + _addToUsage(node.target, createCallReference); } } @@ -45,51 +47,34 @@ void recordConstantExpression(ast.ConstantExpression node) { final constant = node.constant; if (constant is ast.StaticTearOffConstant) { - final hasRecordUseAnnotation = - recordUse.findRecordUseAnnotation(constant.target).isNotEmpty; + final hasRecordUseAnnotation = recordUse.hasRecordUseAnnotation( + constant.target, + ); if (hasRecordUseAnnotation) { - _recordTearOff(constant, node); + _addToUsage( + constant.target, + CallTearOff( + loadingUnit: loadingUnitForNode(node, _loadingUnits).toString(), + location: node.location!.recordLocation(_source, exactLocation), + ), + ); } } } - void _recordTearOff( - ast.StaticTearOffConstant constant, - ast.ConstantExpression node, - ) { - final call = _getCall(constant.target); - final reference = _collectTearOff(constant, node); - call.references.add(reference); - } - - /// Record a tear off as a call with all non-const arguments. - CallReference _collectTearOff( - ast.StaticTearOffConstant constant, - ast.TreeNode node, - ) { - final function = constant.target.function; - final nonConstArguments = NonConstArguments( - named: - function.namedParameters.map((parameter) => parameter.name!).toList(), - positional: List.generate( - function.positionalParameters.length, - (index) => index, - ), - ); - return CallReference( - location: node.location!.recordLocation(_source), - arguments: Arguments(nonConstArguments: nonConstArguments), - ); - } - /// Collect the name and definition location of the invocation. This is /// shared across multiple calls to the same method. - Usage _getCall(ast.Procedure target) { - final definition = _definitionFromMember(target); - return _callsForMethod[target] ??= Usage( - definition: definition, - references: [], + void _addToUsage(ast.Procedure target, CallReference call) { + var (:identifier, :loadingUnit) = _definitionFromMember(target); + callsForMethod.update( + identifier, + (usage) => usage..add(call), + ifAbsent: () => [call], ); + loadingUnitForDefinition.update(identifier, (value) { + assert(value == loadingUnit); + return value; + }, ifAbsent: () => loadingUnit); } CallReference _createCallReference(ast.StaticInvocation node) { @@ -101,49 +86,47 @@ argumentStart = 0; } - final positionalArguments = node.arguments.positional - .skip(argumentStart) - .mapIndexed((i, argument) => MapEntry(i, _evaluateLiteral(argument))); - final namedArguments = node.arguments.named.map( - (argument) => MapEntry(argument.name, _evaluateLiteral(argument.value)), - ); + final positionalArguments = + node.arguments.positional + .skip(argumentStart) + .map((argument) => _evaluateLiteral(argument)) + .toList(); - // Group by the evaluated literal - if it exists, the argument was const. - final positionalGrouped = _groupByNull(positionalArguments); - final namedGrouped = _groupByNull(namedArguments); + final namedArguments = { + for (final argument in node.arguments.named) + argument.name: _evaluateLiteral(argument.value), + }; - return CallReference( - location: node.location!.recordLocation(_source), + // Fill up with the default values + for (final parameter in node.target.function.namedParameters) { + final initializer = parameter.initializer; + final name = parameter.name; + if (initializer != null && + name != null && + !namedArguments.containsKey(name)) { + namedArguments[name] = _evaluateLiteral(initializer); + } + } + for ( + var i = positionalArguments.length; + i < node.target.function.positionalParameters.length; + i++ + ) { + final parameter = node.target.function.positionalParameters[i]; + final initializer = parameter.initializer; + if (initializer != null) { + positionalArguments.add(_evaluateLiteral(initializer)); + } + } + + return CallWithArguments( + positionalArguments: positionalArguments, + namedArguments: namedArguments, loadingUnit: loadingUnitForNode(node, _loadingUnits).toString(), - arguments: Arguments( - constArguments: ConstArguments( - positional: - positionalGrouped[false] != null - ? Map.fromEntries( - positionalGrouped[false]!.map( - (e) => MapEntry(e.key, e.value!), - ), - ) - : null, - named: - namedGrouped[false] != null - ? Map.fromEntries( - namedGrouped[false]!.map((e) => MapEntry(e.key, e.value!)), - ) - : null, - ), - nonConstArguments: NonConstArguments( - positional: positionalGrouped[true]?.map((e) => e.key).toList(), - named: namedGrouped[true]?.map((e) => e.key).toList(), - ), - ), + location: node.location!.recordLocation(_source, exactLocation), ); } - Map<bool, List<MapEntry<T, Constant?>>> _groupByNull<T>( - Iterable<MapEntry<T, Constant?>> arguments, - ) => groupBy(arguments, (entry) => entry.value == null); - Constant? _evaluateLiteral(ast.Expression expression) { if (expression is ast.BasicLiteral) { return evaluateLiteral(expression); @@ -154,17 +137,18 @@ } } - Definition _definitionFromMember(ast.Member target) { + ({Identifier identifier, String loadingUnit}) _definitionFromMember( + ast.Member target, + ) { final enclosingLibrary = target.enclosingLibrary; String file = getImportUri(enclosingLibrary, _source); - return Definition( + return ( identifier: Identifier( importUri: file, - parent: target.enclosingClass?.name, + scope: target.enclosingClass?.name, name: target.name.text, ), - location: target.location!.recordLocation(_source), loadingUnit: loadingUnitForNode(enclosingLibrary, _loadingUnits).toString(), );
diff --git a/pkg/vm/lib/transformations/record_use/record_instance.dart b/pkg/vm/lib/transformations/record_use/record_instance.dart index 0ae0926..35c0229 100644 --- a/pkg/vm/lib/transformations/record_use/record_instance.dart +++ b/pkg/vm/lib/transformations/record_use/record_instance.dart
@@ -10,15 +10,15 @@ import 'constant_collector.dart'; /// Record a const instance by calling [recordConstantExpression]. After all the -/// const instances have been recorded, retrieve them using [foundInstances]. +/// const instances have been recorded, retrieve them using [instancesForClass]. class InstanceRecorder { - /// The collection of recorded instances found so far. - Iterable<Usage<InstanceReference>> get foundInstances => - _instancesForClass.values; - /// Keep track of the classes which are recorded, to easily add found /// instances. - final Map<ast.Class, Usage<InstanceReference>> _instancesForClass = {}; + final Map<Identifier, List<InstanceReference>> instancesForClass = {}; + + /// Keep track of the calls which are recorded, to easily add newly found + /// ones. + final Map<Identifier, String> loadingUnitForDefinition = {}; /// The ordered list of loading units to retrieve the loading unit index from. final List<LoadingUnit> _loadingUnits; @@ -29,6 +29,10 @@ /// A visitor traversing and collecting constants. late final ConstantCollector collector; + /// Whether to save line and column info as well as the URI. + //TODO(mosum): add verbose mode to enable this + bool exactLocation = false; + InstanceRecorder(this._source, this._loadingUnits) { collector = ConstantCollector.collectWith(_collectInstance); } @@ -40,33 +44,33 @@ ast.ConstantExpression expression, ast.InstanceConstant constant, ) { - // Collect the name and definition location of the invocation. This is - // shared across multiple calls to the same method. - final existingInstance = _getCall(constant.classNode); - - // Collect the (int, bool, double, or String) arguments passed in the call. - existingInstance.references.add( - _createInstanceReference(expression, constant), - ); + final instance = _createInstanceReference(expression, constant); + _addToUsage(constant.classNode, instance); } /// Collect the name and definition location of the invocation. This is /// shared across multiple calls to the same method. - Usage<InstanceReference> _getCall(ast.Class cls) { - final definition = _definitionFromClass(cls); - return _instancesForClass[cls] ??= Usage( - definition: definition, - references: [], + void _addToUsage(ast.Class cls, InstanceReference instance) { + var (:identifier, :loadingUnit) = _definitionFromClass(cls); + instancesForClass.update( + identifier, + (usage) => usage..add(instance), + ifAbsent: () => [instance], ); + loadingUnitForDefinition.update(identifier, (value) { + assert(value == loadingUnit); + return value; + }, ifAbsent: () => loadingUnit); } - Definition _definitionFromClass(ast.Class cls) { + ({Identifier identifier, String loadingUnit}) _definitionFromClass( + ast.Class cls, + ) { final enclosingLibrary = cls.enclosingLibrary; final file = getImportUri(enclosingLibrary, _source); - return Definition( + return ( identifier: Identifier(importUri: file, name: cls.name), - location: cls.location!.recordLocation(_source), loadingUnit: loadingUnitForNode(cls.enclosingLibrary, _loadingUnits).toString(), ); @@ -76,7 +80,7 @@ ast.ConstantExpression expression, ast.InstanceConstant constant, ) => InstanceReference( - location: expression.location!.recordLocation(_source), + location: expression.location!.recordLocation(_source, exactLocation), instanceConstant: _fieldsFromConstant(constant), loadingUnit: loadingUnitForNode(expression, _loadingUnits).toString(), );
diff --git a/pkg/vm/lib/transformations/record_use/record_use.dart b/pkg/vm/lib/transformations/record_use/record_use.dart index 5515220..b58e957 100644 --- a/pkg/vm/lib/transformations/record_use/record_use.dart +++ b/pkg/vm/lib/transformations/record_use/record_use.dart
@@ -36,15 +36,24 @@ component.metadata[tag] as LoadingUnitsMetadataRepository; final loadingUnits = loadingMetadata.mapping[component]?.loadingUnits ?? []; - final staticCallRecorder = CallRecorder(source, loadingUnits); - final instanceUseRecorder = InstanceRecorder(source, loadingUnits); - component.accept(_RecordUseVisitor(staticCallRecorder, instanceUseRecorder)); + final callRecorder = CallRecorder(source, loadingUnits); + final instanceRecorder = InstanceRecorder(source, loadingUnits); + component.accept(_RecordUseVisitor(callRecorder, instanceRecorder)); final usages = _usages( - staticCallRecorder.foundCalls, - instanceUseRecorder.foundInstances, + callRecorder.callsForMethod, + instanceRecorder.instancesForClass, + mergeMaps( + callRecorder.loadingUnitForDefinition, + instanceRecorder.loadingUnitForDefinition, + value: (p0, p1) { + // The loading units for the same definition should be the same + assert(p0 == p1); + return p0; + }, + ), ); - var usagesStorageFormat = usages.toJson(); + final usagesStorageFormat = usages.toJson(); File.fromUri(recordedUsagesFile).writeAsStringSync( JsonEncoder.withIndent(' ').convert(usagesStorageFormat), ); @@ -74,18 +83,29 @@ } } -UsageRecord _usages( - Iterable<Usage<CallReference>> calls, - Iterable<Usage<InstanceReference>> instances, +Recordings _usages( + Map<Identifier, List<CallReference>> calls, + Map<Identifier, List<InstanceReference>> instances, + Map<Identifier, String> loadingUnitForDefinition, ) { - return UsageRecord( - metadata: Metadata( - comment: + return Recordings( + metadata: Metadata.fromJson({ + 'comment': 'Recorded usages of objects tagged with a `RecordUse` annotation', - version: Version(0, 1, 0), + 'version': Version(0, 2, 0).toString(), + }), + callsForDefinition: calls.map( + (key, value) => MapEntry( + Definition(identifier: key, loadingUnit: loadingUnitForDefinition[key]), + value, + ), ), - calls: calls.toList(), - instances: instances.toList(), + instancesForDefinition: instances.map( + (key, value) => MapEntry( + Definition(identifier: key, loadingUnit: loadingUnitForDefinition[key]), + value, + ), + ), ); } @@ -135,10 +155,10 @@ throw UnsupportedError('$constantType is not supported for recording.'); extension RecordUseLocation on ast.Location { - Location recordLocation(Uri source) => Location( + Location recordLocation(Uri source, bool exactLocation) => Location( uri: relativizeUri(source, this.file, Platform.isWindows), - line: line, - column: column, + line: exactLocation ? line : null, + column: exactLocation ? column : null, ); }
diff --git a/pkg/vm/lib/transformations/type_flow/signature_shaking.dart b/pkg/vm/lib/transformations/type_flow/signature_shaking.dart index ce30bb0..69d52f4 100644 --- a/pkg/vm/lib/transformations/type_flow/signature_shaking.dart +++ b/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
@@ -6,7 +6,7 @@ import 'package:kernel/core_types.dart'; import 'package:kernel/type_environment.dart'; import 'package:front_end/src/api_unstable/vm.dart' show isExtensionTypeThis; -import 'package:front_end/src/api_prototype/record_use.dart' as RecordUse; +import 'package:front_end/src/api_prototype/record_use.dart' as recordUse; import 'analysis.dart'; import 'table_selector_assigner.dart'; @@ -223,8 +223,7 @@ /// Disable signature shaking for annotated methods, to prevent removal of /// parameters. The consumers of recorded_usages.json expect constant /// argument values to be present for all parameters. - if (member is Procedure && - RecordUse.findRecordUseAnnotation(member).isNotEmpty) { + if (member is Procedure && recordUse.hasRecordUseAnnotation(member)) { isChecked = true; } } @@ -268,7 +267,8 @@ .isMemberReferencedFromNativeCode(member) || shaker.typeFlowAnalysis.nativeCodeOracle.isRecognized(member) || member.isExternal || - member.name.text == '==') { + member.name.text == '==' || + recordUse.hasRecordUseAnnotation(member)) { info.eligible = false; } }
diff --git a/pkg/vm/test/transformations/record_use_test.dart b/pkg/vm/test/transformations/record_use_test.dart index fc4c5df..c597316 100644 --- a/pkg/vm/test/transformations/record_use_test.dart +++ b/pkg/vm/test/transformations/record_use_test.dart
@@ -79,14 +79,12 @@ final testCasesDir = Directory.fromUri( _pkgVmDir.resolve('testcases/transformations/record_use/'), ); - for (var file in testCasesDir .listSync(recursive: true, followLinks: false) .reversed) { if (file.path.endsWith('.dart') && !file.path.contains('helper') && - !file.path.contains('instance_complex') && (filter == null || file.path.contains(filter))) { test( '${file.path} aot',
diff --git a/pkg/vm/testcases/transformations/record_use/complex.dart.json.expect b/pkg/vm/testcases/transformations/record_use/complex.dart.json.expect index f8087c4..b9496ea 100644 --- a/pkg/vm/testcases/transformations/record_use/complex.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/complex.dart.json.expect
@@ -1,58 +1,41 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "complex.dart" - ], - "ids": [ - { - "uri": 0, - "parent": "OtherClass", - "name": "generate" - } - ], "constants": [ { "type": "int", "value": 42 } ], - "calls": [ + "locations": [ + { + "uri": "complex.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 24, - "column": 25 + "identifier": { + "uri": "complex.dart", + "scope": "OtherClass", + "name": "generate" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "calls": [ { - "arguments": { - "const": { - "positional": { - "4": 0 - } - }, - "nonConst": { - "positional": [ - 0, - 1, - 2, - 3 - ] - } - }, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 20, - "column": 18 - } + "type": "with_arguments", + "positional": [ + null, + null, + null, + null, + 0 + ], + "loading_unit": "1", + "@": 0 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/different.dart.json.expect b/pkg/vm/testcases/transformations/record_use/different.dart.json.expect index d95dcdd..e463d4d 100644 --- a/pkg/vm/testcases/transformations/record_use/different.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/different.dart.json.expect
@@ -1,9 +1,6 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" - }, - "uris": [], - "ids": [], - "constants": [] + "version": "0.2.0" + } } \ No newline at end of file
diff --git a/pkg/vm/testcases/transformations/record_use/extension.dart.json.expect b/pkg/vm/testcases/transformations/record_use/extension.dart.json.expect index 7440708..a911545 100644 --- a/pkg/vm/testcases/transformations/record_use/extension.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/extension.dart.json.expect
@@ -1,49 +1,36 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "extension.dart" - ], - "ids": [ - { - "uri": 0, - "name": "_extension#0|callWithArgs" - } - ], "constants": [ { "type": "String", "value": "42" } ], - "calls": [ + "locations": [ + { + "uri": "extension.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 15, - "column": 8 + "identifier": { + "uri": "extension.dart", + "name": "_extension#0|callWithArgs" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "calls": [ { - "arguments": { - "const": { - "positional": { - "0": 0 - } - } - }, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 8, - "column": 15 - } + "type": "with_arguments", + "positional": [ + 0 + ], + "loading_unit": "1", + "@": 0 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/instance_class.dart.json.expect b/pkg/vm/testcases/transformations/record_use/instance_class.dart.json.expect index 799526f..937c503 100644 --- a/pkg/vm/testcases/transformations/record_use/instance_class.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/instance_class.dart.json.expect
@@ -1,17 +1,8 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "instance_class.dart" - ], - "ids": [ - { - "uri": 0, - "name": "MyClass" - } - ], "constants": [ { "type": "int", @@ -24,26 +15,25 @@ } } ], - "instances": [ + "locations": [ + { + "uri": "instance_class.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 15, - "column": 7 + "identifier": { + "uri": "instance_class.dart", + "name": "MyClass" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "instances": [ { - "instanceConstant": 1, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 11, - "column": 2 - } + "constant_index": 1, + "loading_unit": "1", + "@": 0 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/instance_complex.dart.json.expect b/pkg/vm/testcases/transformations/record_use/instance_complex.dart.json.expect index 8f9d5ce..e8eb867 100644 --- a/pkg/vm/testcases/transformations/record_use/instance_complex.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/instance_complex.dart.json.expect
@@ -1,17 +1,8 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "instance_complex.dart" - ], - "ids": [ - { - "uri": 0, - "name": "MyClass" - } - ], "constants": [ { "type": "int", @@ -66,26 +57,25 @@ } } ], - "instances": [ + "locations": [ + { + "uri": "instance_complex.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 24, - "column": 7 + "identifier": { + "uri": "instance_complex.dart", + "name": "MyClass" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "instances": [ { - "instanceConstant": 9, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 11, - "column": 2 - } + "constant_index": 9, + "loading_unit": "1", + "@": 0 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/instance_duplicates.dart.json.expect b/pkg/vm/testcases/transformations/record_use/instance_duplicates.dart.json.expect index 9559444..815b624 100644 --- a/pkg/vm/testcases/transformations/record_use/instance_duplicates.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/instance_duplicates.dart.json.expect
@@ -1,17 +1,8 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "instance_duplicates.dart" - ], - "ids": [ - { - "uri": 0, - "name": "MyClass" - } - ], "constants": [ { "type": "int", @@ -34,35 +25,30 @@ } } ], - "instances": [ + "locations": [ + { + "uri": "instance_duplicates.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 14, - "column": 7 + "identifier": { + "uri": "instance_duplicates.dart", + "name": "MyClass" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "instances": [ { - "instanceConstant": 1, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 8, - "column": 15 - } + "constant_index": 1, + "loading_unit": "1", + "@": 0 }, { - "instanceConstant": 3, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 10, - "column": 15 - } + "constant_index": 3, + "loading_unit": "1", + "@": 0 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/instance_method.dart.json.expect b/pkg/vm/testcases/transformations/record_use/instance_method.dart.json.expect index e3ff3df..4fb90b6 100644 --- a/pkg/vm/testcases/transformations/record_use/instance_method.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/instance_method.dart.json.expect
@@ -1,17 +1,8 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "instance_method.dart" - ], - "ids": [ - { - "uri": 0, - "name": "MyClass" - } - ], "constants": [ { "type": "int", @@ -24,26 +15,25 @@ } } ], - "instances": [ + "locations": [ + { + "uri": "instance_method.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 17, - "column": 7 + "identifier": { + "uri": "instance_method.dart", + "name": "MyClass" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "instances": [ { - "instanceConstant": 1, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 11, - "column": 2 - } + "constant_index": 1, + "loading_unit": "1", + "@": 0 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/instance_not_annotation.dart.json.expect b/pkg/vm/testcases/transformations/record_use/instance_not_annotation.dart.json.expect index f2d8bb1..b15ce8e 100644 --- a/pkg/vm/testcases/transformations/record_use/instance_not_annotation.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/instance_not_annotation.dart.json.expect
@@ -1,42 +1,32 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "instance_not_annotation.dart" - ], - "ids": [ - { - "uri": 0, - "name": "MyClass" - } - ], "constants": [ { "type": "Instance" } ], - "instances": [ + "locations": [ + { + "uri": "instance_not_annotation.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 13, - "column": 7 + "identifier": { + "uri": "instance_not_annotation.dart", + "name": "MyClass" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "instances": [ { - "instanceConstant": 0, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 9, - "column": 9 - } + "constant_index": 0, + "loading_unit": "1", + "@": 0 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/loading_units_multiple.dart.json.expect b/pkg/vm/testcases/transformations/record_use/loading_units_multiple.dart.json.expect index 049870b..6bc799f 100644 --- a/pkg/vm/testcases/transformations/record_use/loading_units_multiple.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/loading_units_multiple.dart.json.expect
@@ -1,67 +1,48 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "loading_units_multiple_helper_shared.dart", - "loading_units_multiple.dart", - "loading_units_multiple_helper.dart" - ], - "ids": [ - { - "uri": 0, - "parent": "SomeClass", - "name": "someStaticMethod" - } - ], "constants": [ { "type": "int", "value": 42 } ], - "calls": [ + "locations": [ + { + "uri": "loading_units_multiple.dart" + }, + { + "uri": "loading_units_multiple_helper.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 9, - "column": 15 + "identifier": { + "uri": "loading_units_multiple_helper_shared.dart", + "scope": "SomeClass", + "name": "someStaticMethod" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "calls": [ { - "arguments": { - "const": { - "positional": { - "0": 0 - } - } - }, - "loadingUnit": "1", - "@": { - "uri": 1, - "line": 12, - "column": 13 - } + "type": "with_arguments", + "positional": [ + 0 + ], + "loading_unit": "1", + "@": 0 }, { - "arguments": { - "const": { - "positional": { - "0": 0 - } - } - }, - "loadingUnit": "2", - "@": { - "uri": 2, - "line": 8, - "column": 13 - } + "type": "with_arguments", + "positional": [ + 0 + ], + "loading_unit": "2", + "@": 1 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/loading_units_simple.dart.json.expect b/pkg/vm/testcases/transformations/record_use/loading_units_simple.dart.json.expect index e1708ee..0a46bc9 100644 --- a/pkg/vm/testcases/transformations/record_use/loading_units_simple.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/loading_units_simple.dart.json.expect
@@ -1,84 +1,60 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "loading_units_simple.dart", - "loading_units_simple_helper.dart" - ], - "ids": [ - { - "uri": 0, - "parent": "SomeClass", - "name": "someStaticMethod" - }, - { - "uri": 1, - "parent": "SomeClass", - "name": "someStaticMethod" - } - ], "constants": [ { "type": "int", "value": 42 } ], - "calls": [ + "locations": [ + { + "uri": "loading_units_simple.dart" + }, + { + "uri": "loading_units_simple_helper.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 23, - "column": 15 + "identifier": { + "uri": "loading_units_simple.dart", + "scope": "SomeClass", + "name": "someStaticMethod" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "calls": [ { - "arguments": { - "const": { - "positional": { - "0": 0 - } - } - }, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 14, - "column": 13 - } + "type": "with_arguments", + "positional": [ + 0 + ], + "loading_unit": "1", + "@": 0 } ] }, { "definition": { - "id": 1, - "@": { - "uri": 1, - "line": 13, - "column": 15 + "identifier": { + "uri": "loading_units_simple_helper.dart", + "scope": "SomeClass", + "name": "someStaticMethod" }, - "loadingUnit": "2" + "loading_unit": "2" }, - "references": [ + "calls": [ { - "arguments": { - "const": { - "positional": { - "0": 0 - } - } - }, - "loadingUnit": "2", - "@": { - "uri": 1, - "line": 8, - "column": 13 - } + "type": "with_arguments", + "positional": [ + 0 + ], + "loading_unit": "2", + "@": 1 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/named_and_positional.dart b/pkg/vm/testcases/transformations/record_use/named_and_positional.dart new file mode 100644 index 0000000..cb412cc --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/named_and_positional.dart
@@ -0,0 +1,19 @@ +// Copyright (c) 2023, 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:meta/meta.dart' show RecordUse; + +void main() { + print(SomeClass.someStaticMethod(3)); + print(SomeClass.someStaticMethod(5, k: 1)); + print(SomeClass.someStaticMethod(5, l: 2)); + print(SomeClass.someStaticMethod(5, l: 2, k: 4)); +} + +class SomeClass { + @RecordUse() + static someStaticMethod(int i, {int? l, int k = 3}) { + return i + 1; + } +}
diff --git a/pkg/vm/testcases/transformations/record_use/named_and_positional.dart.aot.expect b/pkg/vm/testcases/transformations/record_use/named_and_positional.dart.aot.expect new file mode 100644 index 0000000..cc6ba32 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/named_and_positional.dart.aot.expect
@@ -0,0 +1,29 @@ +library #lib; +import self as self; +import "dart:core" as core; +import "package:meta/meta.dart" as meta; + +import "package:meta/meta.dart" show RecordUse; + +abstract class SomeClass extends core::Object { + + [@vm.inferred-return-type.metadata=int] + [@vm.unboxing-info.metadata=(i)->i] + @#C1 + static method someStaticMethod([@vm.inferred-arg-type.metadata=dart.core::_Smi] core::int i, {[@vm.inferred-arg-type.metadata=dart.core::_Smi?] core::int? l = #C2, [@vm.inferred-arg-type.metadata=dart.core::_Smi] core::int k = #C3}) → dynamic { + return [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(1){(core::num) → core::int}; + } +} + +[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] +static method main() → void { + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(3)); + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(5, k: 1)); + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(5, l: 2)); + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(5, l: 2, k: 4)); +} +constants { + #C1 = meta::RecordUse {} + #C2 = null + #C3 = 3 +}
diff --git a/pkg/vm/testcases/transformations/record_use/named_and_positional.dart.json.expect b/pkg/vm/testcases/transformations/record_use/named_and_positional.dart.json.expect new file mode 100644 index 0000000..8173d9f --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/named_and_positional.dart.json.expect
@@ -0,0 +1,98 @@ +{ + "metadata": { + "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", + "version": "0.2.0" + }, + "constants": [ + { + "type": "int", + "value": 3 + }, + { + "type": "Null" + }, + { + "type": "int", + "value": 5 + }, + { + "type": "int", + "value": 1 + }, + { + "type": "int", + "value": 2 + }, + { + "type": "int", + "value": 4 + } + ], + "locations": [ + { + "uri": "named_and_positional.dart" + } + ], + "recordings": [ + { + "definition": { + "identifier": { + "uri": "named_and_positional.dart", + "scope": "SomeClass", + "name": "someStaticMethod" + }, + "loading_unit": "1" + }, + "calls": [ + { + "type": "with_arguments", + "positional": [ + 0 + ], + "named": { + "l": 1, + "k": 0 + }, + "loading_unit": "1", + "@": 0 + }, + { + "type": "with_arguments", + "positional": [ + 2 + ], + "named": { + "k": 3, + "l": 1 + }, + "loading_unit": "1", + "@": 0 + }, + { + "type": "with_arguments", + "positional": [ + 2 + ], + "named": { + "l": 4, + "k": 0 + }, + "loading_unit": "1", + "@": 0 + }, + { + "type": "with_arguments", + "positional": [ + 2 + ], + "named": { + "l": 4, + "k": 5 + }, + "loading_unit": "1", + "@": 0 + } + ] + } + ] +} \ No newline at end of file
diff --git a/pkg/vm/testcases/transformations/record_use/named_both.dart b/pkg/vm/testcases/transformations/record_use/named_both.dart new file mode 100644 index 0000000..cb90355 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/named_both.dart
@@ -0,0 +1,19 @@ +// Copyright (c) 2023, 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:meta/meta.dart' show RecordUse; + +void main() { + print(SomeClass.someStaticMethod(i: 3)); + print(SomeClass.someStaticMethod(i: 5, k: 1)); + print(SomeClass.someStaticMethod(i: 5, l: 2)); + print(SomeClass.someStaticMethod(i: 5, l: 2, k: 4)); +} + +class SomeClass { + @RecordUse() + static someStaticMethod({required int i, int? l, int k = 3}) { + return i + 1; + } +}
diff --git a/pkg/vm/testcases/transformations/record_use/named_both.dart.aot.expect b/pkg/vm/testcases/transformations/record_use/named_both.dart.aot.expect new file mode 100644 index 0000000..3161222 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/named_both.dart.aot.expect
@@ -0,0 +1,29 @@ +library #lib; +import self as self; +import "dart:core" as core; +import "package:meta/meta.dart" as meta; + +import "package:meta/meta.dart" show RecordUse; + +abstract class SomeClass extends core::Object { + + [@vm.inferred-return-type.metadata=int] + [@vm.unboxing-info.metadata=()->i] + @#C1 + static method someStaticMethod({[@vm.inferred-arg-type.metadata=dart.core::_Smi] required core::int i, [@vm.inferred-arg-type.metadata=dart.core::_Smi?] core::int? l = #C2, [@vm.inferred-arg-type.metadata=dart.core::_Smi] core::int k = #C3}) → dynamic { + return [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(1){(core::num) → core::int}; + } +} + +[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] +static method main() → void { + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(i: 3)); + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(i: 5, k: 1)); + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(i: 5, l: 2)); + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(i: 5, l: 2, k: 4)); +} +constants { + #C1 = meta::RecordUse {} + #C2 = null + #C3 = 3 +}
diff --git a/pkg/vm/testcases/transformations/record_use/named_both.dart.json.expect b/pkg/vm/testcases/transformations/record_use/named_both.dart.json.expect new file mode 100644 index 0000000..6554aa1 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/named_both.dart.json.expect
@@ -0,0 +1,90 @@ +{ + "metadata": { + "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", + "version": "0.2.0" + }, + "constants": [ + { + "type": "int", + "value": 3 + }, + { + "type": "Null" + }, + { + "type": "int", + "value": 5 + }, + { + "type": "int", + "value": 1 + }, + { + "type": "int", + "value": 2 + }, + { + "type": "int", + "value": 4 + } + ], + "locations": [ + { + "uri": "named_both.dart" + } + ], + "recordings": [ + { + "definition": { + "identifier": { + "uri": "named_both.dart", + "scope": "SomeClass", + "name": "someStaticMethod" + }, + "loading_unit": "1" + }, + "calls": [ + { + "type": "with_arguments", + "named": { + "i": 0, + "l": 1, + "k": 0 + }, + "loading_unit": "1", + "@": 0 + }, + { + "type": "with_arguments", + "named": { + "i": 2, + "k": 3, + "l": 1 + }, + "loading_unit": "1", + "@": 0 + }, + { + "type": "with_arguments", + "named": { + "i": 2, + "l": 4, + "k": 0 + }, + "loading_unit": "1", + "@": 0 + }, + { + "type": "with_arguments", + "named": { + "i": 2, + "l": 4, + "k": 5 + }, + "loading_unit": "1", + "@": 0 + } + ] + } + ] +} \ No newline at end of file
diff --git a/pkg/vm/testcases/transformations/record_use/named_optional.dart b/pkg/vm/testcases/transformations/record_use/named_optional.dart new file mode 100644 index 0000000..05f37b1 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/named_optional.dart
@@ -0,0 +1,17 @@ +// Copyright (c) 2023, 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:meta/meta.dart' show RecordUse; + +void main() { + print(SomeClass.someStaticMethod(i: 3)); + print(SomeClass.someStaticMethod()); +} + +class SomeClass { + @RecordUse() + static someStaticMethod({int i = 4}) { + return i + 1; + } +}
diff --git a/pkg/vm/testcases/transformations/record_use/named_optional.dart.aot.expect b/pkg/vm/testcases/transformations/record_use/named_optional.dart.aot.expect new file mode 100644 index 0000000..0745099 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/named_optional.dart.aot.expect
@@ -0,0 +1,26 @@ +library #lib; +import self as self; +import "dart:core" as core; +import "package:meta/meta.dart" as meta; + +import "package:meta/meta.dart" show RecordUse; + +abstract class SomeClass extends core::Object { + + [@vm.inferred-return-type.metadata=int] + [@vm.unboxing-info.metadata=()->i] + @#C1 + static method someStaticMethod({[@vm.inferred-arg-type.metadata=dart.core::_Smi] core::int i = #C2}) → dynamic { + return [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(1){(core::num) → core::int}; + } +} + +[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] +static method main() → void { + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(i: 3)); + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod()); +} +constants { + #C1 = meta::RecordUse {} + #C2 = 4 +}
diff --git a/pkg/vm/testcases/transformations/record_use/named_optional.dart.json.expect b/pkg/vm/testcases/transformations/record_use/named_optional.dart.json.expect new file mode 100644 index 0000000..6ab0085 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/named_optional.dart.json.expect
@@ -0,0 +1,51 @@ +{ + "metadata": { + "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", + "version": "0.2.0" + }, + "constants": [ + { + "type": "int", + "value": 3 + }, + { + "type": "int", + "value": 4 + } + ], + "locations": [ + { + "uri": "named_optional.dart" + } + ], + "recordings": [ + { + "definition": { + "identifier": { + "uri": "named_optional.dart", + "scope": "SomeClass", + "name": "someStaticMethod" + }, + "loading_unit": "1" + }, + "calls": [ + { + "type": "with_arguments", + "named": { + "i": 0 + }, + "loading_unit": "1", + "@": 0 + }, + { + "type": "with_arguments", + "named": { + "i": 1 + }, + "loading_unit": "1", + "@": 0 + } + ] + } + ] +} \ No newline at end of file
diff --git a/pkg/vm/testcases/transformations/record_use/named_required.dart b/pkg/vm/testcases/transformations/record_use/named_required.dart new file mode 100644 index 0000000..cedddc6 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/named_required.dart
@@ -0,0 +1,17 @@ +// Copyright (c) 2023, 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:meta/meta.dart' show RecordUse; + +void main() { + print(SomeClass.someStaticMethod(i: 3)); + print(SomeClass.someStaticMethod(i: 5)); +} + +class SomeClass { + @RecordUse() + static someStaticMethod({required int i}) { + return i + 1; + } +}
diff --git a/pkg/vm/testcases/transformations/record_use/named_required.dart.aot.expect b/pkg/vm/testcases/transformations/record_use/named_required.dart.aot.expect new file mode 100644 index 0000000..758584b --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/named_required.dart.aot.expect
@@ -0,0 +1,25 @@ +library #lib; +import self as self; +import "dart:core" as core; +import "package:meta/meta.dart" as meta; + +import "package:meta/meta.dart" show RecordUse; + +abstract class SomeClass extends core::Object { + + [@vm.inferred-return-type.metadata=int] + [@vm.unboxing-info.metadata=()->i] + @#C1 + static method someStaticMethod({[@vm.inferred-arg-type.metadata=dart.core::_Smi] required core::int i}) → dynamic { + return [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(1){(core::num) → core::int}; + } +} + +[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] +static method main() → void { + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(i: 3)); + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(i: 5)); +} +constants { + #C1 = meta::RecordUse {} +}
diff --git a/pkg/vm/testcases/transformations/record_use/named_required.dart.json.expect b/pkg/vm/testcases/transformations/record_use/named_required.dart.json.expect new file mode 100644 index 0000000..2b9cd08 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/named_required.dart.json.expect
@@ -0,0 +1,51 @@ +{ + "metadata": { + "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", + "version": "0.2.0" + }, + "constants": [ + { + "type": "int", + "value": 3 + }, + { + "type": "int", + "value": 5 + } + ], + "locations": [ + { + "uri": "named_required.dart" + } + ], + "recordings": [ + { + "definition": { + "identifier": { + "uri": "named_required.dart", + "scope": "SomeClass", + "name": "someStaticMethod" + }, + "loading_unit": "1" + }, + "calls": [ + { + "type": "with_arguments", + "named": { + "i": 0 + }, + "loading_unit": "1", + "@": 0 + }, + { + "type": "with_arguments", + "named": { + "i": 1 + }, + "loading_unit": "1", + "@": 0 + } + ] + } + ] +} \ No newline at end of file
diff --git a/pkg/vm/testcases/transformations/record_use/nested.dart.json.expect b/pkg/vm/testcases/transformations/record_use/nested.dart.json.expect index 560496d..eb0bfe4 100644 --- a/pkg/vm/testcases/transformations/record_use/nested.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/nested.dart.json.expect
@@ -1,21 +1,8 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "nested.dart" - ], - "ids": [ - { - "uri": 0, - "name": "MyClass" - }, - { - "uri": 0, - "name": "MyOtherClass" - } - ], "constants": [ { "type": "int", @@ -41,57 +28,46 @@ "type": "Instance" } ], - "instances": [ + "locations": [ + { + "uri": "nested.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 16, - "column": 7 + "identifier": { + "uri": "nested.dart", + "name": "MyClass" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "instances": [ { - "instanceConstant": 1, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 12, - "column": 9 - } + "constant_index": 1, + "loading_unit": "1", + "@": 0 }, { - "instanceConstant": 3, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 12, - "column": 9 - } + "constant_index": 3, + "loading_unit": "1", + "@": 0 } ] }, { "definition": { - "id": 1, - "@": { - "uri": 0, - "line": 23, - "column": 7 + "identifier": { + "uri": "nested.dart", + "name": "MyOtherClass" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "instances": [ { - "instanceConstant": 4, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 12, - "column": 9 - } + "constant_index": 4, + "loading_unit": "1", + "@": 0 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/partfile_main.dart.json.expect b/pkg/vm/testcases/transformations/record_use/partfile_main.dart.json.expect index 397f6bc..7401831 100644 --- a/pkg/vm/testcases/transformations/record_use/partfile_main.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/partfile_main.dart.json.expect
@@ -1,51 +1,37 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "partfile_main.dart", - "partfile_helper.dart" - ], - "ids": [ - { - "uri": 0, - "parent": "SomeClass", - "name": "someStaticMethod" - } - ], "constants": [ { "type": "int", "value": 42 } ], - "calls": [ + "locations": [ + { + "uri": "partfile_main.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 1, - "line": 9, - "column": 10 + "identifier": { + "uri": "partfile_main.dart", + "scope": "SomeClass", + "name": "someStaticMethod" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "calls": [ { - "arguments": { - "const": { - "positional": { - "0": 0 - } - } - }, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 9, - "column": 19 - } + "type": "with_arguments", + "positional": [ + 0 + ], + "loading_unit": "1", + "@": 0 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/positional_both.dart b/pkg/vm/testcases/transformations/record_use/positional_both.dart new file mode 100644 index 0000000..4277e30 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/positional_both.dart
@@ -0,0 +1,17 @@ +// Copyright (c) 2023, 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:meta/meta.dart' show RecordUse; + +void main() { + print(SomeClass.someStaticMethod(5, 3)); + print(SomeClass.someStaticMethod(6)); +} + +class SomeClass { + @RecordUse() + static someStaticMethod(int k, [int i = 4]) { + return i + 1; + } +}
diff --git a/pkg/vm/testcases/transformations/record_use/positional_both.dart.aot.expect b/pkg/vm/testcases/transformations/record_use/positional_both.dart.aot.expect new file mode 100644 index 0000000..ae0525d --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/positional_both.dart.aot.expect
@@ -0,0 +1,26 @@ +library #lib; +import self as self; +import "dart:core" as core; +import "package:meta/meta.dart" as meta; + +import "package:meta/meta.dart" show RecordUse; + +abstract class SomeClass extends core::Object { + + [@vm.inferred-return-type.metadata=int] + [@vm.unboxing-info.metadata=(i)->i] + @#C1 + static method someStaticMethod([@vm.inferred-arg-type.metadata=dart.core::_Smi] core::int k, [[@vm.inferred-arg-type.metadata=dart.core::_Smi] core::int i = #C2]) → dynamic { + return [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(1){(core::num) → core::int}; + } +} + +[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] +static method main() → void { + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(5, 3)); + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(6)); +} +constants { + #C1 = meta::RecordUse {} + #C2 = 4 +}
diff --git a/pkg/vm/testcases/transformations/record_use/positional_both.dart.json.expect b/pkg/vm/testcases/transformations/record_use/positional_both.dart.json.expect new file mode 100644 index 0000000..a12ed12 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/positional_both.dart.json.expect
@@ -0,0 +1,61 @@ +{ + "metadata": { + "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", + "version": "0.2.0" + }, + "constants": [ + { + "type": "int", + "value": 5 + }, + { + "type": "int", + "value": 3 + }, + { + "type": "int", + "value": 6 + }, + { + "type": "int", + "value": 4 + } + ], + "locations": [ + { + "uri": "positional_both.dart" + } + ], + "recordings": [ + { + "definition": { + "identifier": { + "uri": "positional_both.dart", + "scope": "SomeClass", + "name": "someStaticMethod" + }, + "loading_unit": "1" + }, + "calls": [ + { + "type": "with_arguments", + "positional": [ + 0, + 1 + ], + "loading_unit": "1", + "@": 0 + }, + { + "type": "with_arguments", + "positional": [ + 2, + 3 + ], + "loading_unit": "1", + "@": 0 + } + ] + } + ] +} \ No newline at end of file
diff --git a/pkg/vm/testcases/transformations/record_use/positional_optional.dart b/pkg/vm/testcases/transformations/record_use/positional_optional.dart new file mode 100644 index 0000000..5c09560 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/positional_optional.dart
@@ -0,0 +1,17 @@ +// Copyright (c) 2023, 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:meta/meta.dart' show RecordUse; + +void main() { + print(SomeClass.someStaticMethod(3)); + print(SomeClass.someStaticMethod()); +} + +class SomeClass { + @RecordUse() + static someStaticMethod([int i = 4]) { + return i + 1; + } +}
diff --git a/pkg/vm/testcases/transformations/record_use/positional_optional.dart.aot.expect b/pkg/vm/testcases/transformations/record_use/positional_optional.dart.aot.expect new file mode 100644 index 0000000..8ded2fbf --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/positional_optional.dart.aot.expect
@@ -0,0 +1,26 @@ +library #lib; +import self as self; +import "dart:core" as core; +import "package:meta/meta.dart" as meta; + +import "package:meta/meta.dart" show RecordUse; + +abstract class SomeClass extends core::Object { + + [@vm.inferred-return-type.metadata=int] + [@vm.unboxing-info.metadata=()->i] + @#C1 + static method someStaticMethod([[@vm.inferred-arg-type.metadata=dart.core::_Smi] core::int i = #C2]) → dynamic { + return [@vm.direct-call.metadata=dart.core::_IntegerImplementation.+] [@vm.inferred-type.metadata=int (skip check)] i.{core::num::+}(1){(core::num) → core::int}; + } +} + +[@vm.inferred-return-type.metadata=dart.core::Null? (value: null)] +static method main() → void { + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod(3)); + core::print([@vm.inferred-type.metadata=int] self::SomeClass::someStaticMethod()); +} +constants { + #C1 = meta::RecordUse {} + #C2 = 4 +}
diff --git a/pkg/vm/testcases/transformations/record_use/positional_optional.dart.json.expect b/pkg/vm/testcases/transformations/record_use/positional_optional.dart.json.expect new file mode 100644 index 0000000..9bf24a4 --- /dev/null +++ b/pkg/vm/testcases/transformations/record_use/positional_optional.dart.json.expect
@@ -0,0 +1,51 @@ +{ + "metadata": { + "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", + "version": "0.2.0" + }, + "constants": [ + { + "type": "int", + "value": 3 + }, + { + "type": "int", + "value": 4 + } + ], + "locations": [ + { + "uri": "positional_optional.dart" + } + ], + "recordings": [ + { + "definition": { + "identifier": { + "uri": "positional_optional.dart", + "scope": "SomeClass", + "name": "someStaticMethod" + }, + "loading_unit": "1" + }, + "calls": [ + { + "type": "with_arguments", + "positional": [ + 0 + ], + "loading_unit": "1", + "@": 0 + }, + { + "type": "with_arguments", + "positional": [ + 1 + ], + "loading_unit": "1", + "@": 0 + } + ] + } + ] +} \ No newline at end of file
diff --git a/pkg/vm/testcases/transformations/record_use/simple.dart.json.expect b/pkg/vm/testcases/transformations/record_use/simple.dart.json.expect index 72d9f63..f78583c 100644 --- a/pkg/vm/testcases/transformations/record_use/simple.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/simple.dart.json.expect
@@ -1,50 +1,37 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "simple.dart" - ], - "ids": [ - { - "uri": 0, - "parent": "SomeClass", - "name": "someStaticMethod" - } - ], "constants": [ { "type": "int", "value": 42 } ], - "calls": [ + "locations": [ + { + "uri": "simple.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 13, - "column": 10 + "identifier": { + "uri": "simple.dart", + "scope": "SomeClass", + "name": "someStaticMethod" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "calls": [ { - "arguments": { - "const": { - "positional": { - "0": 0 - } - } - }, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 8, - "column": 19 - } + "type": "with_arguments", + "positional": [ + 0 + ], + "loading_unit": "1", + "@": 0 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/tearoff.dart.json.expect b/pkg/vm/testcases/transformations/record_use/tearoff.dart.json.expect index 7699d75..777ad9e 100644 --- a/pkg/vm/testcases/transformations/record_use/tearoff.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/tearoff.dart.json.expect
@@ -1,45 +1,28 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "tearoff.dart" - ], - "ids": [ + "locations": [ { - "uri": 0, - "parent": "SomeClass", - "name": "someStaticMethod" + "uri": "tearoff.dart" } ], - "constants": [], - "calls": [ + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 15, - "column": 10 + "identifier": { + "uri": "tearoff.dart", + "scope": "SomeClass", + "name": "someStaticMethod" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "calls": [ { - "arguments": { - "nonConst": { - "positional": [ - 0 - ] - } - }, - "loadingUnit": null, - "@": { - "uri": 0, - "line": 11, - "column": 27 - } + "type": "tearoff", + "loading_unit": "1", + "@": 0 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/top_level_method.dart.json.expect b/pkg/vm/testcases/transformations/record_use/top_level_method.dart.json.expect index e0a2a0a..c3cf404 100644 --- a/pkg/vm/testcases/transformations/record_use/top_level_method.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/top_level_method.dart.json.expect
@@ -1,49 +1,36 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "top_level_method.dart" - ], - "ids": [ - { - "uri": 0, - "name": "someTopLevelMethod" - } - ], "constants": [ { "type": "int", "value": 42 } ], - "calls": [ + "locations": [ + { + "uri": "top_level_method.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 12, - "column": 5 + "identifier": { + "uri": "top_level_method.dart", + "name": "someTopLevelMethod" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "calls": [ { - "arguments": { - "const": { - "positional": { - "0": 0 - } - } - }, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 8, - "column": 9 - } + "type": "with_arguments", + "positional": [ + 0 + ], + "loading_unit": "1", + "@": 0 } ] }
diff --git a/pkg/vm/testcases/transformations/record_use/types_of_arguments.dart.json.expect b/pkg/vm/testcases/transformations/record_use/types_of_arguments.dart.json.expect index 82ab669..64c863f 100644 --- a/pkg/vm/testcases/transformations/record_use/types_of_arguments.dart.json.expect +++ b/pkg/vm/testcases/transformations/record_use/types_of_arguments.dart.json.expect
@@ -1,18 +1,8 @@ { "metadata": { "comment": "Recorded usages of objects tagged with a `RecordUse` annotation", - "version": "0.1.0" + "version": "0.2.0" }, - "uris": [ - "types_of_arguments.dart" - ], - "ids": [ - { - "uri": 0, - "parent": "SomeClass", - "name": "someStaticMethod" - } - ], "constants": [ { "type": "int", @@ -67,107 +57,69 @@ } } ], - "calls": [ + "locations": [ + { + "uri": "types_of_arguments.dart" + } + ], + "recordings": [ { "definition": { - "id": 0, - "@": { - "uri": 0, - "line": 24, - "column": 17 + "identifier": { + "uri": "types_of_arguments.dart", + "scope": "SomeClass", + "name": "someStaticMethod" }, - "loadingUnit": "1" + "loading_unit": "1" }, - "references": [ + "calls": [ { - "arguments": { - "const": { - "positional": { - "0": 0 - } - } - }, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 8, - "column": 19 - } + "type": "with_arguments", + "positional": [ + 0 + ], + "loading_unit": "1", + "@": 0 }, { - "arguments": { - "const": { - "positional": { - "0": 1 - } - } - }, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 9, - "column": 19 - } + "type": "with_arguments", + "positional": [ + 1 + ], + "loading_unit": "1", + "@": 0 }, { - "arguments": { - "const": { - "positional": { - "0": 2 - } - } - }, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 10, - "column": 19 - } + "type": "with_arguments", + "positional": [ + 2 + ], + "loading_unit": "1", + "@": 0 }, { - "arguments": { - "const": { - "positional": { - "0": 3 - } - } - }, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 11, - "column": 19 - } + "type": "with_arguments", + "positional": [ + 3 + ], + "loading_unit": "1", + "@": 0 }, { - "arguments": { - "const": { - "positional": { - "0": 10 - } - } - }, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 13, - "column": 15 - } + "type": "with_arguments", + "positional": [ + 10 + ], + "loading_unit": "1", + "@": 0 }, { - "arguments": { - "nonConst": { - "positional": [ - 0 - ] - } - }, - "loadingUnit": "1", - "@": { - "uri": 0, - "line": 19, - "column": 19 - } + "type": "with_arguments", + "positional": [ + null + ], + "loading_unit": "1", + "@": 0 } ] }
diff --git a/tools/VERSION b/tools/VERSION index e7c998d..0b1d217 100644 --- a/tools/VERSION +++ b/tools/VERSION
@@ -27,5 +27,5 @@ MAJOR 3 MINOR 9 PATCH 0 -PRERELEASE 64 +PRERELEASE 65 PRERELEASE_PATCH 0