Elements. Migrate SinceSdkVersionComputer.

Change-Id: Iecc9e796903e3c3791db42b4678ee2511477e7fb
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/403928
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
Reviewed-by: Phil Quitslund <pquitslund@google.com>
diff --git a/pkg/analyzer/lib/dart/element/element2.dart b/pkg/analyzer/lib/dart/element/element2.dart
index 55ec4f8..7c4c221 100644
--- a/pkg/analyzer/lib/dart/element/element2.dart
+++ b/pkg/analyzer/lib/dart/element/element2.dart
@@ -256,7 +256,8 @@
 /// type.
 ///
 /// Clients may not extend, implement or mix-in this class.
-abstract class ConstructorElement2 implements ExecutableElement2 {
+abstract class ConstructorElement2
+    implements ExecutableElement2, HasSinceSdkVersion {
   @override
   ConstructorElement2 get baseElement;
 
@@ -845,7 +846,11 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class FormalParameterElement
-    implements PromotableElement2, Annotatable, LocalElement2 {
+    implements
+        PromotableElement2,
+        Annotatable,
+        HasSinceSdkVersion,
+        LocalElement2 {
   @override
   FormalParameterElement get baseElement;
 
@@ -1140,11 +1145,35 @@
   // GetterElement get element;
 }
 
+/// The interface that is implemented by elements that can have `@Since()`
+/// annotation.
+abstract class HasSinceSdkVersion {
+  /// The version where the associated SDK API was added.
+  ///
+  /// A `@Since()` annotation can be applied to a library declaration,
+  /// any public declaration in a library, or in a class, or to an optional
+  /// parameter, etc.
+  ///
+  /// The returned version is "effective", so that if a library is annotated
+  /// then all elements of the library inherit it; or if a class is annotated
+  /// then all members and constructors of the class inherit it.
+  ///
+  /// If multiple `@Since()` annotations apply to the same element, the latest
+  /// version takes precedence.
+  ///
+  /// Returns `null` if the element is not declared in the SDK, or doesn't have
+  /// a `@Since()` annotation applied to it.
+  Version? get sinceSdkVersion;
+}
+
 /// An element whose instance members can refer to `this`.
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class InstanceElement2
-    implements TypeDefiningElement2, TypeParameterizedElement2 {
+    implements
+        TypeDefiningElement2,
+        TypeParameterizedElement2,
+        HasSinceSdkVersion {
   @override
   LibraryElement2 get enclosingElement2;
 
@@ -1474,7 +1503,8 @@
 /// A library.
 ///
 /// Clients may not extend, implement or mix-in this class.
-abstract class LibraryElement2 implements Element2, Annotatable {
+abstract class LibraryElement2
+    implements Element2, Annotatable, HasSinceSdkVersion {
   /// The classes defined in this library.
   ///
   /// There is no guarantee of the order in which the classes will be returned.
@@ -1958,23 +1988,6 @@
 
   /// Whether the receiver has an annotation of the form `@widgetFactory`.
   bool get hasWidgetFactory;
-
-  /// The version where the associated SDK API was added.
-  ///
-  /// A `@Since()` annotation can be applied to a library declaration,
-  /// any public declaration in a library, or in a class, or to an optional
-  /// parameter, etc.
-  ///
-  /// The returned version is "effective", so that if a library is annotated
-  /// then all elements of the library inherit it; or if a class is annotated
-  /// then all members and constructors of the class inherit it.
-  ///
-  /// If multiple `@Since()` annotations apply to the same element, the latest
-  /// version takes precedence.
-  ///
-  /// Returns `null` if the element is not declared in the SDK, or doesn't have
-  /// a `@Since()` annotation applied to it.
-  Version? get sinceSdkVersion;
 }
 
 /// A method.
@@ -1983,7 +1996,8 @@
 /// method.
 ///
 /// Clients may not extend, implement or mix-in this class.
-abstract class MethodElement2 implements ExecutableElement2 {
+abstract class MethodElement2
+    implements ExecutableElement2, HasSinceSdkVersion {
   /// The name of the method that can be implemented by a class to allow its
   /// instances to be invoked as if they were a function.
   static final String CALL_METHOD_NAME = "call";
@@ -2277,7 +2291,7 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class PropertyInducingElement2
-    implements VariableElement2, Annotatable {
+    implements VariableElement2, Annotatable, HasSinceSdkVersion {
   @override
   PropertyInducingFragment get firstFragment;
 
@@ -2439,7 +2453,8 @@
 /// A top-level function.
 ///
 /// Clients may not extend, implement or mix-in this class.
-abstract class TopLevelFunctionElement implements ExecutableElement2 {
+abstract class TopLevelFunctionElement
+    implements ExecutableElement2, HasSinceSdkVersion {
   @override
   TopLevelFunctionElement get baseElement;
 
@@ -2512,7 +2527,10 @@
 ///
 /// Clients may not extend, implement or mix-in this class.
 abstract class TypeAliasElement2
-    implements TypeParameterizedElement2, TypeDefiningElement2 {
+    implements
+        TypeParameterizedElement2,
+        TypeDefiningElement2,
+        HasSinceSdkVersion {
   /// If the aliased type has structure, return the corresponding element.
   /// For example, it could be [GenericFunctionTypeElement].
   ///
diff --git a/pkg/analyzer/lib/src/dart/element/element.dart b/pkg/analyzer/lib/src/dart/element/element.dart
index 8d4c8c6..d70ac76 100644
--- a/pkg/analyzer/lib/src/dart/element/element.dart
+++ b/pkg/analyzer/lib/src/dart/element/element.dart
@@ -1612,7 +1612,8 @@
         FragmentedFunctionTypedElementMixin<ConstructorFragment>,
         FragmentedTypeParameterizedElementMixin<ConstructorFragment>,
         FragmentedAnnotatableElementMixin<ConstructorFragment>,
-        FragmentedElementMixin<ConstructorFragment>
+        FragmentedElementMixin<ConstructorFragment>,
+        _HasSinceSdkVersionMixin
     implements ConstructorElement2 {
   @override
   final String? name3;
@@ -2077,7 +2078,7 @@
 
   @override
   Metadata get metadata2 {
-    return MetadataImpl(0, const [], () => null);
+    return MetadataImpl(0, const []);
   }
 
   @override
@@ -2507,14 +2508,6 @@
   static const _metadataFlag_hasDeprecated = 1 << 1;
   static const _metadataFlag_hasOverride = 1 << 2;
 
-  /// Cached values for [sinceSdkVersion].
-  ///
-  /// Only very few elements have `@Since()` annotations, so instead of adding
-  /// an instance field to [ElementImpl], we attach this information this way.
-  /// We ask it only when [Modifier.HAS_SINCE_SDK_VERSION_VALUE] is `true`, so
-  /// don't pay for a hash lookup when we know that the result is `null`.
-  static final Expando<Version> _sinceSdkVersion = Expando<Version>();
-
   static int _NEXT_ID = 0;
 
   @override
@@ -3010,8 +3003,7 @@
     _metadata = metadata;
   }
 
-  Metadata get metadata2 =>
-      MetadataImpl(_getMetadataFlags(), metadata, () => sinceSdkVersion);
+  Metadata get metadata2 => MetadataImpl(_getMetadataFlags(), metadata);
 
   @override
   String? get name => _name;
@@ -3049,18 +3041,7 @@
 
   @override
   Version? get sinceSdkVersion {
-    if (!hasModifier(Modifier.HAS_SINCE_SDK_VERSION_COMPUTED)) {
-      setModifier(Modifier.HAS_SINCE_SDK_VERSION_COMPUTED, true);
-      var result = SinceSdkVersionComputer().compute(this);
-      if (result != null) {
-        _sinceSdkVersion[this] = result;
-        setModifier(Modifier.HAS_SINCE_SDK_VERSION_VALUE, true);
-      }
-    }
-    if (hasModifier(Modifier.HAS_SINCE_SDK_VERSION_VALUE)) {
-      return _sinceSdkVersion[this];
-    }
-    return null;
+    return asElement2.ifTypeOrNull<HasSinceSdkVersion>()?.sinceSdkVersion;
   }
 
   @override
@@ -3315,6 +3296,9 @@
   @override
   final int id = ElementImpl._NEXT_ID++;
 
+  /// The modifiers associated with this element.
+  EnumSet<Modifier> _modifiers = EnumSet.empty();
+
   @override
   Element2 get baseElement => this;
 
@@ -3401,6 +3385,9 @@
     return "$shortName (${source?.fullName})";
   }
 
+  /// Whether this element has the [modifier].
+  bool hasModifier(Modifier modifier) => _modifiers[modifier];
+
   @override
   bool isAccessibleIn2(LibraryElement2 library) {
     var name3 = this.name3;
@@ -3410,6 +3397,11 @@
     return true;
   }
 
+  /// Update [modifier] of this element to [value].
+  void setModifier(Modifier modifier, bool value) {
+    _modifiers = _modifiers.updated(modifier, value);
+  }
+
   @override
   Element2? thisOrAncestorMatching2(bool Function(Element2 p1) predicate) {
     Element2? element = this;
@@ -4003,6 +3995,7 @@
 }
 
 class ExtensionElementImpl2 extends InstanceElementImpl2
+    with _HasSinceSdkVersionMixin
     implements AugmentedExtensionElement, ExtensionElement2 {
   @override
   final Reference reference;
@@ -4254,7 +4247,8 @@
 class FieldElementImpl2 extends PropertyInducingElementImpl2
     with
         FragmentedAnnotatableElementMixin<FieldElementImpl>,
-        FragmentedElementMixin<FieldElementImpl>
+        FragmentedElementMixin<FieldElementImpl>,
+        _HasSinceSdkVersionMixin
     implements FieldElement2 {
   @override
   final FieldElementImpl firstFragment;
@@ -4402,6 +4396,7 @@
         FragmentedAnnotatableElementMixin<FormalParameterFragment>,
         FragmentedElementMixin<FormalParameterFragment>,
         FormalParameterElementMixin,
+        _HasSinceSdkVersionMixin,
         _NonTopLevelVariableOrParameter
     implements FormalParameterElementOrMember {
   final ParameterElementImpl wrappedElement;
@@ -4885,12 +4880,12 @@
     return result;
   }
 
-  Metadata get metadata2 => MetadataImpl(
-      -1, metadata.cast<ElementAnnotationImpl>(), () => sinceSdkVersion);
+  Metadata get metadata2 =>
+      MetadataImpl(-1, metadata.cast<ElementAnnotationImpl>());
 
   Version? get sinceSdkVersion {
     if (this is Element2) {
-      return SinceSdkVersionComputer().compute2(this as Element2);
+      return SinceSdkVersionComputer().compute(this as Element2);
     }
     return null;
   }
@@ -5332,7 +5327,8 @@
         FragmentedFunctionTypedElementMixin<GetterFragment>,
         FragmentedTypeParameterizedElementMixin<GetterFragment>,
         FragmentedAnnotatableElementMixin<GetterFragment>,
-        FragmentedElementMixin<GetterFragment>
+        FragmentedElementMixin<GetterFragment>,
+        _HasSinceSdkVersionMixin
     implements GetterElement {
   @override
   final PropertyAccessorElementImpl firstFragment;
@@ -5366,6 +5362,14 @@
   }
 
   @override
+  Version? get sinceSdkVersion {
+    if (isSynthetic) {
+      return variable3?.sinceSdkVersion;
+    }
+    return super.sinceSdkVersion;
+  }
+
+  @override
   T? accept2<T>(ElementVisitor2<T> visitor) {
     return visitor.visitGetterElement(this);
   }
@@ -6353,6 +6357,7 @@
 }
 
 abstract class InterfaceElementImpl2 extends InstanceElementImpl2
+    with _HasSinceSdkVersionMixin
     implements AugmentedInterfaceElement, InterfaceElement2 {
   @override
   List<InterfaceType> interfaces = [];
@@ -7043,6 +7048,11 @@
   }
 
   @override
+  Version? get sinceSdkVersion {
+    return SinceSdkVersionComputer().compute(this);
+  }
+
+  @override
   Source get source {
     return _definingCompilationUnit.source;
   }
@@ -7642,10 +7652,7 @@
   @override
   final List<ElementAnnotationImpl> annotations;
 
-  final Version? Function() _sinceSdkVersionComputer;
-
-  MetadataImpl(
-      this._metadataFlags, this.annotations, this._sinceSdkVersionComputer);
+  MetadataImpl(this._metadataFlags, this.annotations);
 
   @override
   bool get hasAlwaysThrows {
@@ -8003,9 +8010,6 @@
     }
     return false;
   }
-
-  @override
-  Version? get sinceSdkVersion => _sinceSdkVersionComputer();
 }
 
 /// A concrete implementation of a [MethodElement].
@@ -8109,7 +8113,8 @@
         FragmentedFunctionTypedElementMixin<MethodFragment>,
         FragmentedTypeParameterizedElementMixin<MethodFragment>,
         FragmentedAnnotatableElementMixin<MethodFragment>,
-        FragmentedElementMixin<MethodFragment>
+        FragmentedElementMixin<MethodFragment>,
+        _HasSinceSdkVersionMixin
     implements MethodElement2 {
   @override
   final Reference reference;
@@ -8922,7 +8927,7 @@
 
   @override
   Metadata get metadata2 {
-    return MetadataImpl(0, const [], () => null);
+    return MetadataImpl(0, const []);
   }
 
   @override
@@ -10141,7 +10146,8 @@
         FragmentedFunctionTypedElementMixin<SetterFragment>,
         FragmentedTypeParameterizedElementMixin<SetterFragment>,
         FragmentedAnnotatableElementMixin<SetterFragment>,
-        FragmentedElementMixin<SetterFragment>
+        FragmentedElementMixin<SetterFragment>,
+        _HasSinceSdkVersionMixin
     implements SetterElement {
   @override
   final PropertyAccessorElementImpl firstFragment;
@@ -10186,6 +10192,14 @@
   }
 
   @override
+  Version? get sinceSdkVersion {
+    if (isSynthetic) {
+      return variable3?.sinceSdkVersion;
+    }
+    return super.sinceSdkVersion;
+  }
+
+  @override
   T? accept2<T>(ElementVisitor2<T> visitor) {
     return visitor.visitSetterElement(this);
   }
@@ -10316,7 +10330,8 @@
         FragmentedFunctionTypedElementMixin<TopLevelFunctionFragment>,
         FragmentedTypeParameterizedElementMixin<TopLevelFunctionFragment>,
         FragmentedAnnotatableElementMixin<TopLevelFunctionFragment>,
-        FragmentedElementMixin<TopLevelFunctionFragment>
+        FragmentedElementMixin<TopLevelFunctionFragment>,
+        _HasSinceSdkVersionMixin
     implements TopLevelFunctionElement {
   @override
   final Reference reference;
@@ -10415,7 +10430,8 @@
 class TopLevelVariableElementImpl2 extends PropertyInducingElementImpl2
     with
         FragmentedAnnotatableElementMixin<TopLevelVariableElementImpl>,
-        FragmentedElementMixin<TopLevelVariableElementImpl>
+        FragmentedElementMixin<TopLevelVariableElementImpl>,
+        _HasSinceSdkVersionMixin
     implements TopLevelVariableElement2 {
   @override
   final Reference reference;
@@ -10736,7 +10752,8 @@
 class TypeAliasElementImpl2 extends TypeDefiningElementImpl2
     with
         FragmentedAnnotatableElementMixin<TypeAliasFragment>,
-        FragmentedElementMixin<TypeAliasFragment>
+        FragmentedElementMixin<TypeAliasFragment>,
+        _HasSinceSdkVersionMixin
     implements TypeAliasElement2 {
   @override
   final Reference reference;
@@ -11314,6 +11331,34 @@
   Source get source => enclosingElement3!.source!;
 }
 
+mixin _HasSinceSdkVersionMixin
+    on ElementImpl2, Annotatable
+    implements HasSinceSdkVersion {
+  /// Cached values for [sinceSdkVersion].
+  ///
+  /// Only very few elements have `@Since()` annotations, so instead of adding
+  /// an instance field to [ElementImpl2], we attach this information this way.
+  /// We ask it only when [Modifier.HAS_SINCE_SDK_VERSION_VALUE] is `true`, so
+  /// don't pay for a hash lookup when we know that the result is `null`.
+  static final Expando<Version> _sinceSdkVersion = Expando<Version>();
+
+  @override
+  Version? get sinceSdkVersion {
+    if (!hasModifier(Modifier.HAS_SINCE_SDK_VERSION_COMPUTED)) {
+      setModifier(Modifier.HAS_SINCE_SDK_VERSION_COMPUTED, true);
+      var result = SinceSdkVersionComputer().compute(this);
+      if (result != null) {
+        _sinceSdkVersion[this] = result;
+        setModifier(Modifier.HAS_SINCE_SDK_VERSION_VALUE, true);
+      }
+    }
+    if (hasModifier(Modifier.HAS_SINCE_SDK_VERSION_VALUE)) {
+      return _sinceSdkVersion[this];
+    }
+    return null;
+  }
+}
+
 mixin _NonTopLevelVariableOrParameter on Element2 {
   @override
   Element2? get enclosingElement2 {
@@ -11381,7 +11426,7 @@
   Metadata get metadataOrEmpty {
     return switch (this) {
       Annotatable(:var metadata2) => metadata2,
-      _ => MetadataImpl(-1, const [], () => null),
+      _ => MetadataImpl(-1, const []),
     };
   }
 }
diff --git a/pkg/analyzer/lib/src/dart/element/since_sdk_version.dart b/pkg/analyzer/lib/src/dart/element/since_sdk_version.dart
index 0bbb26f..edbf3cd 100644
--- a/pkg/analyzer/lib/src/dart/element/since_sdk_version.dart
+++ b/pkg/analyzer/lib/src/dart/element/since_sdk_version.dart
@@ -2,8 +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.
 
-// ignore_for_file: analyzer_use_new_elements
-
 import 'package:analyzer/dart/element/element2.dart';
 import 'package:analyzer/src/dart/ast/ast.dart';
 import 'package:analyzer/src/dart/element/element.dart';
@@ -14,49 +12,13 @@
 
   /// The [element] is a `dart:xyz` library, so it can have `@Since` annotations.
   /// Evaluates its annotations and returns the version.
-  Version? compute(ElementImpl element) {
-    // Must be in a `dart:` library.
-    var librarySource = element.librarySource;
-    if (librarySource == null || !librarySource.uri.isScheme('dart')) {
-      return null;
-    }
-
-    // Fields cannot be referenced outside.
-    if (element is FieldElementImpl && element.isSynthetic) {
-      return null;
-    }
-
-    // We cannot add required parameters.
-    if (element is ParameterElementImpl && element.isRequired) {
-      return null;
-    }
-
-    var specified = _specifiedVersion(element);
-    if (element.enclosingElement3 case var enclosingElement?) {
-      var enclosing = enclosingElement.sinceSdkVersion;
-      return specified.maxWith(enclosing);
-    } else if (element.library case var libraryElement?) {
-      var enclosing = libraryElement.sinceSdkVersion;
-      return specified.maxWith(enclosing);
-    } else {
-      return specified;
-    }
-  }
-
-  /// The [element] is a `dart:xyz` library, so it can have `@Since` annotations.
-  /// Evaluates its annotations and returns the version.
-  Version? compute2(Element2 element) {
+  Version? compute(Element2 element) {
     // Must be in a `dart:` library.
     var libraryUri = element.library2?.uri;
     if (libraryUri == null || !libraryUri.isScheme('dart')) {
       return null;
     }
 
-    // Fields cannot be referenced outside.
-    if (element is FieldElement2 && element.isSynthetic) {
-      return null;
-    }
-
     // We cannot add required parameters.
     if (element is FormalParameterElement && element.isRequired) {
       return null;
@@ -64,13 +26,13 @@
 
     Version? specified;
     if (element is Annotatable) {
-      specified = _specifiedVersion2(element as Annotatable);
+      specified = _specifiedVersion(element as Annotatable);
     }
-    if (element.enclosingElement2 case Annotatable enclosingElement?) {
-      var enclosing = enclosingElement.metadata2.sinceSdkVersion;
-      return specified.maxWith(enclosing);
-    } else if (element.library2 case var libraryElement?) {
-      var enclosing = libraryElement.metadata2.sinceSdkVersion;
+
+    if (element is LibraryElement2) {
+      return specified;
+    } else if (element.enclosingElement2 case HasSinceSdkVersion hasSince?) {
+      var enclosing = hasSince.sinceSdkVersion;
       return specified.maxWith(enclosing);
     } else {
       return specified;
@@ -93,26 +55,7 @@
   }
 
   /// Returns the maximal specified `@Since()` version, `null` if none.
-  static Version? _specifiedVersion(ElementImpl element) {
-    Version? result;
-    for (var annotation in element.metadata) {
-      if (annotation.isDartInternalSince) {
-        var arguments = annotation.annotationAst.arguments?.arguments;
-        var versionNode = arguments?.singleOrNull;
-        if (versionNode is SimpleStringLiteralImpl) {
-          var versionStr = versionNode.value;
-          var version = _parseVersion(versionStr);
-          if (version != null) {
-            result = result.maxWith(version);
-          }
-        }
-      }
-    }
-    return result;
-  }
-
-  /// Returns the maximal specified `@Since()` version, `null` if none.
-  static Version? _specifiedVersion2(Annotatable element) {
+  static Version? _specifiedVersion(Annotatable element) {
     var annotations =
         element.metadata2.annotations.cast<ElementAnnotationImpl>();
     Version? result;
diff --git a/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart b/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart
index b5780a9..94236e5 100644
--- a/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart
+++ b/pkg/analyzer/lib/src/hint/sdk_constraint_verifier.dart
@@ -165,8 +165,8 @@
     SyntacticEntity? errorEntity,
   }) {
     element = element?.nonSynthetic2;
-    if (element is Annotatable) {
-      var sinceSdkVersion = (element as Annotatable).metadata2.sinceSdkVersion;
+    if (element case HasSinceSdkVersion hasSince) {
+      var sinceSdkVersion = hasSince.sinceSdkVersion;
       if (sinceSdkVersion != null) {
         if (!_versionConstraint.requiresAtLeast(sinceSdkVersion)) {
           if (errorEntity == null) {
diff --git a/pkg/analyzer/test/src/summary/element_text.dart b/pkg/analyzer/test/src/summary/element_text.dart
index 9e77b89..498662a 100644
--- a/pkg/analyzer/test/src/summary/element_text.dart
+++ b/pkg/analyzer/test/src/summary/element_text.dart
@@ -17,7 +17,6 @@
 import 'package:analyzer/src/summary2/macro_type_location.dart';
 import 'package:analyzer_utilities/testing/tree_string_sink.dart';
 import 'package:collection/collection.dart';
-import 'package:pub_semver/pub_semver.dart';
 import 'package:test/test.dart';
 
 import '../../util/element_printer.dart';
@@ -247,6 +246,7 @@
 
       _writeDocumentation(e.documentationComment);
       _writeMetadata(e.metadata2);
+      _writeSinceSdkVersion(e);
 
       // _writeList(
       //   'libraryExports',
@@ -313,6 +313,7 @@
       _writeFragmentReference('firstFragment', e.firstFragment);
       _writeDocumentation(e.documentationComment);
       _writeMetadata(e.metadata2);
+      _writeSinceSdkVersion(e);
       // _writeDisplayName(e);
 
       _writeElementList(
@@ -566,7 +567,7 @@
       _writeFragmentReference('firstFragment', e.firstFragment);
       // _writeDocumentation(e.documentationComment);
       // _writeMetadata(e.metadata);
-      // _writeSinceSdkVersion(e.sinceSdkVersion);
+      _writeSinceSdkVersion(e);
       // _writeCodeRange(e);
       // _writeTypeInferenceError(e);
       _writeType('type', e.type);
@@ -682,6 +683,7 @@
       _writeFragmentReference('firstFragment', e.firstFragment);
       _writeType('type', e.type);
       _writeMetadata(e.metadata2);
+      _writeSinceSdkVersion(e);
       // _writeCodeRange(e);
       _writeElementList(
         'typeParameters',
@@ -899,6 +901,7 @@
       _writeFragmentReference('firstFragment', e.firstFragment);
       _writeDocumentation(e.documentationComment);
       _writeMetadata(e.metadata2);
+      _writeSinceSdkVersion(e);
 
       expect(e.typeParameters2, isEmpty);
       _writeElementList(
@@ -1035,7 +1038,7 @@
       _writeFragmentReference('firstFragment', e.firstFragment);
       _writeDocumentation(e.documentationComment);
       // _writeMetadata(e.metadata);
-      _writeSinceSdkVersion(e.metadata2.sinceSdkVersion);
+      _writeSinceSdkVersion(e);
       _writeElementList(
           'typeParameters', e, e.typeParameters2, _writeTypeParameterElement);
       _writeMacroDiagnostics(e);
@@ -1181,7 +1184,7 @@
       _writeFragmentReference('previousFragment', f.previousFragment);
       _writeFragmentReference('nextFragment', f.nextFragment);
 
-      _writeMetadata(f.metadata2, includeSince: false);
+      _writeMetadata(f.metadata2);
 
       if (configuration.withImports) {
         var imports = f.libraryImports2.where((import) {
@@ -1246,7 +1249,7 @@
     });
 
     _sink.withIndent(() {
-      _writeMetadata(e.metadata2, includeSince: false);
+      _writeMetadata(e.metadata2);
       // _writeNamespaceCombinators(e.combinators);
     });
   }
@@ -1521,7 +1524,7 @@
     }
   }
 
-  void _writeMetadata(Metadata metadata, {bool includeSince = true}) {
+  void _writeMetadata(Metadata metadata) {
     if (configuration.withMetadata) {
       var annotations = metadata.annotations;
       if (annotations.isNotEmpty) {
@@ -1534,9 +1537,6 @@
         });
       }
     }
-    if (includeSince) {
-      _writeSinceSdkVersion(metadata.sinceSdkVersion);
-    }
   }
 
   void _writeMethodElement(MethodElementImpl2 e) {
@@ -1555,6 +1555,7 @@
       // _writeElementReference(e.enclosingElement2, label: 'enclosingElement2');
       _writeDocumentation(e.documentationComment);
       _writeMetadata(e.metadata2);
+      _writeSinceSdkVersion(e);
       // _writeTypeInferenceError(e);
 
       _writeElementList(
@@ -1687,6 +1688,7 @@
       _writeFragmentReference('firstFragment', e.firstFragment);
       _writeDocumentation(e.documentationComment);
       _writeMetadata(e.metadata2);
+      _writeSinceSdkVersion(e);
 
       expect(e.typeParameters2, isEmpty);
       _writeElementList(
@@ -1766,9 +1768,12 @@
     });
   }
 
-  void _writeSinceSdkVersion(Version? version) {
-    if (version != null) {
-      _sink.writelnWithIndent('sinceSdkVersion: $version');
+  void _writeSinceSdkVersion(Element2 element) {
+    if (element case HasSinceSdkVersion hasSince) {
+      var version = hasSince.sinceSdkVersion;
+      if (version != null) {
+        _sink.writelnWithIndent('sinceSdkVersion: $version');
+      }
     }
   }
 
@@ -1787,6 +1792,7 @@
       _writeFragmentReference('firstFragment', e.firstFragment);
       _writeDocumentation(e.documentationComment);
       _writeMetadata(e.metadata2);
+      _writeSinceSdkVersion(e);
       // _writeCodeRange(e);
       _writeElementList(
         'typeParameters',
@@ -1886,6 +1892,7 @@
       _writeFragmentReference('firstFragment', e.firstFragment);
       _writeDocumentation(e.documentationComment);
       _writeMetadata(e.metadata2);
+      _writeSinceSdkVersion(e);
       // _writeTypeInferenceError(e);
       _writeType('type', e.type);
       // _writeShouldUseTypeForInitializerInference(e);
@@ -1983,6 +1990,7 @@
       _writeFragmentReference('firstFragment', e.firstFragment);
       _writeDocumentation(e.documentationComment);
       _writeMetadata(e.metadata2);
+      _writeSinceSdkVersion(e);
       // _writeCodeRange(e);
       _writeElementList(
           'typeParameters', e, e.typeParameters2, _writeTypeParameterElement);
@@ -2063,7 +2071,7 @@
       //   _writeType('defaultType', defaultType);
       // }
 
-      _writeMetadata(e.metadata2, includeSince: false);
+      _writeMetadata(e.metadata2);
     });
 
     _assertNonSyntheticElementSelf(e);
@@ -2089,7 +2097,7 @@
       //   _writeType('defaultType', defaultType);
       // }
 
-      _writeMetadata(f.metadata2, includeSince: false);
+      _writeMetadata(f.metadata2);
     });
 
     // _assertNonSyntheticElementSelf(f);
diff --git a/pkg/analyzer/test/src/summary/elements/since_sdk_version_test.dart b/pkg/analyzer/test/src/summary/elements/since_sdk_version_test.dart
index 4313461..cd28a44 100644
--- a/pkg/analyzer/test/src/summary/elements/since_sdk_version_test.dart
+++ b/pkg/analyzer/test/src/summary/elements/since_sdk_version_test.dart
@@ -81,7 +81,6 @@
             named @55
               reference: dart:foo::<fragment>::@class::A::@constructor::named
               element: dart:foo::<fragment>::@class::A::@constructor::named#element
-              sinceSdkVersion: 2.15.0
               typeName: A
               typeNameOffset: 53
               periodOffset: 54
@@ -176,12 +175,10 @@
             synthetic get foo
               reference: dart:foo::<fragment>::@class::A::@getter::foo
               element: dart:foo::<fragment>::@class::A::@getter::foo#element
-              sinceSdkVersion: 2.15.0
           setters
             synthetic set foo
               reference: dart:foo::<fragment>::@class::A::@setter::foo
               element: dart:foo::<fragment>::@class::A::@setter::foo#element
-              sinceSdkVersion: 2.15.0
               formalParameters
                 <null-name>
                   element: dart:foo::<fragment>::@class::A::@setter::foo::@parameter::_foo#element
@@ -193,6 +190,7 @@
       fields
         hasInitializer foo
           firstFragment: dart:foo::<fragment>::@class::A::@field::foo
+          sinceSdkVersion: 2.15.0
           type: int
           getter: dart:foo::<fragment>::@class::A::@getter::foo#element
           setter: dart:foo::<fragment>::@class::A::@setter::foo#element
@@ -236,6 +234,7 @@
             synthetic foo @-1
               reference: dart:foo::<fragment>::@class::A::@field::foo
               enclosingElement3: dart:foo::<fragment>::@class::A
+              sinceSdkVersion: 2.15.0
               type: int
           accessors
             get foo @61
@@ -262,7 +261,6 @@
             get foo @61
               reference: dart:foo::<fragment>::@class::A::@getter::foo
               element: dart:foo::<fragment>::@class::A::@getter::foo#element
-              sinceSdkVersion: 2.15.0
   classes
     class A
       reference: dart:foo::@class::A
@@ -271,6 +269,7 @@
       fields
         synthetic foo
           firstFragment: dart:foo::<fragment>::@class::A::@field::foo
+          sinceSdkVersion: 2.15.0
           type: int
           getter: dart:foo::<fragment>::@class::A::@getter::foo#element
       getters
@@ -322,7 +321,6 @@
             foo @58
               reference: dart:foo::<fragment>::@class::A::@method::foo
               element: dart:foo::<fragment>::@class::A::@method::foo#element
-              sinceSdkVersion: 2.15.0
   classes
     class A
       reference: dart:foo::@class::A
@@ -379,7 +377,6 @@
             foo @75
               reference: dart:foo::<fragment>::@class::A::@method::foo
               element: dart:foo::<fragment>::@class::A::@method::foo#element
-              sinceSdkVersion: 2.16.0
   classes
     class A
       reference: dart:foo::@class::A
@@ -436,7 +433,6 @@
             foo @75
               reference: dart:foo::<fragment>::@class::A::@method::foo
               element: dart:foo::<fragment>::@class::A::@method::foo#element
-              sinceSdkVersion: 2.15.0
   classes
     class A
       reference: dart:foo::@class::A
@@ -476,6 +472,7 @@
             synthetic foo @-1
               reference: dart:foo::<fragment>::@class::A::@field::foo
               enclosingElement3: dart:foo::<fragment>::@class::A
+              sinceSdkVersion: 2.15.0
               type: int
           accessors
             set foo= @57
@@ -505,7 +502,6 @@
             set foo @57
               reference: dart:foo::<fragment>::@class::A::@setter::foo
               element: dart:foo::<fragment>::@class::A::@setter::foo#element
-              sinceSdkVersion: 2.15.0
               formalParameters
                 _ @65
                   element: dart:foo::<fragment>::@class::A::@setter::foo::@parameter::_#element
@@ -517,6 +513,7 @@
       fields
         synthetic foo
           firstFragment: dart:foo::<fragment>::@class::A::@field::foo
+          sinceSdkVersion: 2.15.0
           type: int
           setter: dart:foo::<fragment>::@class::A::@setter::foo#element
       setters
@@ -612,7 +609,6 @@
             synthetic get v2
               reference: dart:foo::<fragment>::@enum::E::@getter::v2
               element: dart:foo::<fragment>::@enum::E::@getter::v2#element
-              sinceSdkVersion: 2.15.0
             synthetic get values
               reference: dart:foo::<fragment>::@enum::E::@getter::values
               element: dart:foo::<fragment>::@enum::E::@getter::values#element
@@ -628,6 +624,7 @@
           getter: dart:foo::<fragment>::@enum::E::@getter::v1#element
         static const enumConstant hasInitializer v2
           firstFragment: dart:foo::<fragment>::@enum::E::@field::v2
+          sinceSdkVersion: 2.15.0
           type: E
           getter: dart:foo::<fragment>::@enum::E::@getter::v2#element
         synthetic static const values
@@ -639,6 +636,7 @@
           firstFragment: dart:foo::<fragment>::@enum::E::@getter::v1
         synthetic static get v2
           firstFragment: dart:foo::<fragment>::@enum::E::@getter::v2
+          sinceSdkVersion: 2.15.0
         synthetic static get values
           firstFragment: dart:foo::<fragment>::@enum::E::@getter::values
 ''');
@@ -678,6 +676,7 @@
             synthetic static const values @-1
               reference: dart:foo::<fragment>::@enum::E::@field::values
               enclosingElement3: dart:foo::<fragment>::@enum::E
+              sinceSdkVersion: 2.15.0
               type: List<E>
           accessors
             synthetic static get v @-1
@@ -688,6 +687,7 @@
             synthetic static get values @-1
               reference: dart:foo::<fragment>::@enum::E::@getter::values
               enclosingElement3: dart:foo::<fragment>::@enum::E
+              sinceSdkVersion: 2.15.0
               returnType: List<E>
           methods
             foo @62
@@ -718,7 +718,6 @@
             synthetic get v
               reference: dart:foo::<fragment>::@enum::E::@getter::v
               element: dart:foo::<fragment>::@enum::E::@getter::v#element
-              sinceSdkVersion: 2.15.0
             synthetic get values
               reference: dart:foo::<fragment>::@enum::E::@getter::values
               element: dart:foo::<fragment>::@enum::E::@getter::values#element
@@ -726,7 +725,6 @@
             foo @62
               reference: dart:foo::<fragment>::@enum::E::@method::foo
               element: dart:foo::<fragment>::@enum::E::@method::foo#element
-              sinceSdkVersion: 2.15.0
   enums
     enum E
       reference: dart:foo::@enum::E
@@ -736,10 +734,12 @@
       fields
         static const enumConstant hasInitializer v
           firstFragment: dart:foo::<fragment>::@enum::E::@field::v
+          sinceSdkVersion: 2.15.0
           type: E
           getter: dart:foo::<fragment>::@enum::E::@getter::v#element
         synthetic static const values
           firstFragment: dart:foo::<fragment>::@enum::E::@field::values
+          sinceSdkVersion: 2.15.0
           type: List<E>
           getter: dart:foo::<fragment>::@enum::E::@getter::values#element
       getters
@@ -800,7 +800,6 @@
             foo @69
               reference: dart:foo::<fragment>::@extension::E::@method::foo
               element: dart:foo::<fragment>::@extension::E::@method::foo#element
-              sinceSdkVersion: 2.15.0
   extensions
     extension E
       reference: dart:foo::@extension::E
@@ -858,7 +857,6 @@
             foo @58
               reference: dart:foo::<fragment>::@mixin::M::@method::foo
               element: dart:foo::<fragment>::@mixin::M::@method::foo#element
-              sinceSdkVersion: 2.15.0
   mixins
     mixin M
       reference: dart:foo::@mixin::M
@@ -911,7 +909,6 @@
         foo @46
           reference: dart:foo::<fragment>::@function::foo
           element: dart:foo::@function::foo
-          sinceSdkVersion: 2.15.0
         bar @61
           reference: dart:foo::<fragment>::@function::bar
           element: dart:foo::@function::bar
@@ -959,7 +956,6 @@
         foo @54
           reference: dart:foo::<fragment>::@function::foo
           element: dart:foo::@function::foo
-          sinceSdkVersion: 2.15.3-dev.7
   functions
     foo
       reference: dart:foo::@function::foo
@@ -1000,7 +996,6 @@
         foo @48
           reference: dart:foo::<fragment>::@function::foo
           element: dart:foo::@function::foo
-          sinceSdkVersion: 2.15.3
   functions
     foo
       reference: dart:foo::@function::foo
@@ -1083,7 +1078,6 @@
         foo @56
           reference: dart:foo::<fragment>::@function::foo
           element: dart:foo::@function::foo
-          sinceSdkVersion: 2.15.0
   functions
     foo
       reference: dart:foo::@function::foo
@@ -1138,7 +1132,6 @@
             default p2 @67
               reference: dart:foo::<fragment>::@function::f::@parameter::p2
               element: dart:foo::<fragment>::@function::f::@parameter::p2#element
-              sinceSdkVersion: 2.15.0
   functions
     f
       reference: dart:foo::@function::f
@@ -1197,7 +1190,6 @@
               element: dart:foo::<fragment>::@function::f::@parameter::p1#element
             default p2 @67
               element: dart:foo::<fragment>::@function::f::@parameter::p2#element
-              sinceSdkVersion: 2.15.0
   functions
     f
       reference: dart:foo::@function::f
@@ -1242,7 +1234,6 @@
         A @49
           reference: dart:foo::<fragment>::@typeAlias::A
           element: dart:foo::@typeAlias::A
-          sinceSdkVersion: 2.15.0
   typeAliases
     A
       firstFragment: dart:foo::<fragment>::@typeAlias::A
@@ -1289,13 +1280,11 @@
         hasInitializer foo @47
           reference: dart:foo::<fragment>::@topLevelVariable::foo
           element: dart:foo::@topLevelVariable::foo
-          sinceSdkVersion: 2.15.0
           getter2: dart:foo::<fragment>::@getter::foo
       getters
         synthetic get foo
           reference: dart:foo::<fragment>::@getter::foo
           element: dart:foo::<fragment>::@getter::foo#element
-          sinceSdkVersion: 2.15.0
   topLevelVariables
     final hasInitializer foo
       reference: dart:foo::@topLevelVariable::foo
@@ -1306,6 +1295,7 @@
   getters
     synthetic static get foo
       firstFragment: dart:foo::<fragment>::@getter::foo
+      sinceSdkVersion: 2.15.0
 ''');
   }