Push class modifiers up to ClassOrAugmentationElement.

Change-Id: If99d9e29ec8ca87677a58cd90a68a5dda5c5af9c
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/313183
Reviewed-by: Samuel Rawlins <srawlins@google.com>
Commit-Queue: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
Konstantin Shcheglov 2023-07-11 18:45:20 +00:00 committed by Commit Queue
parent f5080bedb3
commit c54b4bc5d3
8 changed files with 398 additions and 174 deletions

View file

@ -242,18 +242,6 @@ abstract class ClassElement
/// Whether the class or its superclass declares a non-final instance field.
bool get hasNonFinalField;
/// Whether the class is abstract. A class is abstract if it has an
/// explicit `abstract` modifier. Note, that this definition of
/// <i>abstract</i> is different from <i>has unimplemented members</i>.
bool get isAbstract;
/// Whether this class is a base class.
///
/// A class is a base class if it has an explicit `base` modifier, or the
/// class has a `base` induced modifier and [isSealed] is `true` as well.
/// The base modifier allows the class to be extended but not implemented.
bool get isBase;
/// Whether the class can be instantiated.
bool get isConstructable;
@ -268,44 +256,18 @@ abstract class ClassElement
/// covered all possible instances of the type.
bool get isExhaustive;
/// Whether the class is a final class.
///
/// A class is a final class if it has an explicit `final` modifier, or the
/// class has a `final` induced modifier and [isSealed] is `true` as well.
/// The final modifier prohibits this class from being extended, implemented,
/// or mixed in.
bool get isFinal;
/// Whether the class is an inline class.
///
/// A class is an inline class if it has an explicit `inline` modifier.
@experimental
bool get isInline;
/// Whether the class is an interface class.
///
/// A class is an interface class if it has an explicit `interface` modifier,
/// or the class has an `interface` induced modifier and [isSealed] is `true`
/// as well. The interface modifier allows the class to be implemented, but
/// not extended or mixed in.
bool get isInterface;
/// Whether the class is a mixin application.
///
/// A class is a mixin application if it was declared using the syntax
/// `class A = B with C;`.
bool get isMixinApplication;
/// Whether the class is a mixin class.
///
/// A class is a mixin class if it has an explicit `mixin` modifier.
bool get isMixinClass;
/// Whether the class is a sealed class.
///
/// A class is a sealed class if it has an explicit `sealed` modifier.
bool get isSealed;
/// Whether the class can validly be used as a mixin when defining
/// another class.
///
@ -369,6 +331,44 @@ abstract class ClassOrAugmentationElement
@override
ClassElement? get augmentedDeclaration;
/// Whether the class is abstract. A class is abstract if it has an
/// explicit `abstract` modifier. Note, that this definition of
/// <i>abstract</i> is different from <i>has unimplemented members</i>.
bool get isAbstract;
/// Whether this class is a base class.
///
/// A class is a base class if it has an explicit `base` modifier, or the
/// class has a `base` induced modifier and [isSealed] is `true` as well.
/// The base modifier allows the class to be extended but not implemented.
bool get isBase;
/// Whether the class is a final class.
///
/// A class is a final class if it has an explicit `final` modifier, or the
/// class has a `final` induced modifier and [isSealed] is `true` as well.
/// The final modifier prohibits this class from being extended, implemented,
/// or mixed in.
bool get isFinal;
/// Whether the class is an interface class.
///
/// A class is an interface class if it has an explicit `interface` modifier,
/// or the class has an `interface` induced modifier and [isSealed] is `true`
/// as well. The interface modifier allows the class to be implemented, but
/// not extended or mixed in.
bool get isInterface;
/// Whether the class is a mixin class.
///
/// A class is a mixin class if it has an explicit `mixin` modifier.
bool get isMixinClass;
/// Whether the class is a sealed class.
///
/// A class is a sealed class if it has an explicit `sealed` modifier.
bool get isSealed;
}
/// An element representing a compilation unit.

View file

@ -365,16 +365,6 @@ class ClassElementImpl extends ClassOrMixinElementImpl
return definingClass != null && !definingClass.isDartCoreObject;
}
@override
bool get isAbstract {
return hasModifier(Modifier.ABSTRACT);
}
/// Set whether this class is abstract.
set isAbstract(bool isAbstract) {
setModifier(Modifier.ABSTRACT, isAbstract);
}
@override
bool get isConstructable => !isSealed && !isAbstract;
@ -431,15 +421,6 @@ class ClassElementImpl extends ClassOrMixinElementImpl
@override
bool get isExhaustive => isSealed;
@override
bool get isFinal {
return hasModifier(Modifier.FINAL);
}
set isFinal(bool isFinal) {
setModifier(Modifier.FINAL, isFinal);
}
@override
bool get isInline {
return hasModifier(Modifier.INLINE);
@ -449,23 +430,6 @@ class ClassElementImpl extends ClassOrMixinElementImpl
setModifier(Modifier.INLINE, isInline);
}
@override
bool get isInterface {
return hasModifier(Modifier.INTERFACE);
}
set isInterface(bool isInterface) {
setModifier(Modifier.INTERFACE, isInterface);
}
bool get isMacro {
return hasModifier(Modifier.MACRO);
}
set isMacro(bool isMacro) {
setModifier(Modifier.MACRO, isMacro);
}
@override
bool get isMixinApplication {
return hasModifier(Modifier.MIXIN_APPLICATION);
@ -476,24 +440,6 @@ class ClassElementImpl extends ClassOrMixinElementImpl
setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication);
}
@override
bool get isMixinClass {
return hasModifier(Modifier.MIXIN_CLASS);
}
set isMixinClass(bool isMixinClass) {
setModifier(Modifier.MIXIN_CLASS, isMixinClass);
}
@override
bool get isSealed {
return hasModifier(Modifier.SEALED);
}
set isSealed(bool isSealed) {
setModifier(Modifier.SEALED, isSealed);
}
@override
bool get isValidMixin {
final supertype = this.supertype;
@ -697,6 +643,68 @@ mixin ClassOrAugmentationElementMixin on InterfaceOrAugmentationElementMixin
@override
ClassElementImpl? get augmentedDeclaration;
@override
bool get isAbstract {
return hasModifier(Modifier.ABSTRACT);
}
set isAbstract(bool isAbstract) {
setModifier(Modifier.ABSTRACT, isAbstract);
}
@override
bool get isBase {
return hasModifier(Modifier.BASE);
}
set isBase(bool isBase) {
setModifier(Modifier.BASE, isBase);
}
@override
bool get isFinal {
return hasModifier(Modifier.FINAL);
}
set isFinal(bool isFinal) {
setModifier(Modifier.FINAL, isFinal);
}
@override
bool get isInterface {
return hasModifier(Modifier.INTERFACE);
}
set isInterface(bool isInterface) {
setModifier(Modifier.INTERFACE, isInterface);
}
bool get isMacro {
return hasModifier(Modifier.MACRO);
}
set isMacro(bool isMacro) {
setModifier(Modifier.MACRO, isMacro);
}
@override
bool get isMixinClass {
return hasModifier(Modifier.MIXIN_CLASS);
}
set isMixinClass(bool isMixinClass) {
setModifier(Modifier.MIXIN_CLASS, isMixinClass);
}
@override
bool get isSealed {
return hasModifier(Modifier.SEALED);
}
set isSealed(bool isSealed) {
setModifier(Modifier.SEALED, isSealed);
}
}
abstract class ClassOrMixinElementImpl extends InterfaceElementImpl {

View file

@ -656,7 +656,7 @@ class LibraryReader {
offset: resolutionOffset,
);
element.setLinkedData(reference, linkedData);
ClassAugmentationElementFlags.read(_reader, element);
ClassElementFlags.read(_reader, element);
element.typeParameters = _readTypeParameters();
@ -1221,7 +1221,7 @@ class LibraryReader {
offset: resolutionOffset,
);
element.setLinkedData(reference, linkedData);
MixinAugmentationElementFlags.read(_reader, element);
MixinElementFlags.read(_reader, element);
element.typeParameters = _readTypeParameters();

View file

@ -141,7 +141,7 @@ class BundleWriter {
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.name);
ClassAugmentationElementFlags.write(_sink, element);
ClassElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata);
@ -438,7 +438,7 @@ class BundleWriter {
_sink.writeUInt30(_resolutionSink.offset);
_sink._writeStringReference(element.name);
MixinAugmentationElementFlags.write(_sink, element);
MixinElementFlags.write(_sink, element);
_resolutionSink._writeAnnotationList(element.metadata);

View file

@ -92,6 +92,16 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
final name = nameToken.lexeme;
final element = ClassAugmentationElementImpl(name, nameToken.offset);
element.isAbstract = node.abstractKeyword != null;
element.isBase = node.baseKeyword != null;
element.isFinal = node.finalKeyword != null;
element.isInterface = node.interfaceKeyword != null;
element.isMacro = node.macroKeyword != null;
element.isMixinClass = node.mixinKeyword != null;
if (node.sealedKeyword != null) {
element.isAbstract = true;
element.isSealed = true;
}
element.metadata = _buildAnnotations(node.metadata);
_setCodeRange(element, node);
_setDocumentation(element, node);
@ -143,16 +153,16 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
var element = ClassElementImpl(name, nameToken.offset);
element.isAbstract = node.abstractKeyword != null;
element.isMacro = node.macroKeyword != null;
if (node.sealedKeyword != null) {
element.isSealed = true;
element.isAbstract = true;
}
element.isBase = node.baseKeyword != null;
element.isInterface = node.interfaceKeyword != null;
element.isFinal = node.finalKeyword != null;
element.isInline = node.inlineKeyword != null;
element.isInterface = node.interfaceKeyword != null;
element.isMacro = node.macroKeyword != null;
element.isMixinClass = node.mixinKeyword != null;
if (node.sealedKeyword != null) {
element.isAbstract = true;
element.isSealed = true;
}
element.metadata = _buildAnnotations(node.metadata);
_setCodeRange(element, node);
_setDocumentation(element, node);
@ -186,16 +196,16 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
var element = ClassElementImpl(name, nameToken.offset);
element.isAbstract = node.abstractKeyword != null;
element.isMacro = node.macroKeyword != null;
if (node.sealedKeyword != null) {
element.isSealed = true;
element.isAbstract = true;
}
element.isBase = node.baseKeyword != null;
element.isInterface = node.interfaceKeyword != null;
element.isFinal = node.finalKeyword != null;
element.isInterface = node.interfaceKeyword != null;
element.isMacro = node.macroKeyword != null;
element.isMixinApplication = true;
element.isMixinClass = node.mixinKeyword != null;
if (node.sealedKeyword != null) {
element.isAbstract = true;
element.isSealed = true;
}
element.metadata = _buildAnnotations(node.metadata);
_setCodeRange(element, node);
_setDocumentation(element, node);

View file

@ -6,20 +6,6 @@ import 'package:analyzer/src/dart/element/element.dart';
import 'package:analyzer/src/summary2/data_reader.dart';
import 'package:analyzer/src/summary2/data_writer.dart';
class ClassAugmentationElementFlags {
static void read(
SummaryDataReader reader,
ClassAugmentationElementImpl element,
) {
reader.readUInt30();
}
static void write(BufferedSink sink, ClassAugmentationElementImpl element) {
var result = 0;
sink.writeUInt30(result);
}
}
class ClassElementFlags {
static const int _isAbstract = 1 << 0;
static const int _isBase = 1 << 1;
@ -32,32 +18,50 @@ class ClassElementFlags {
static const int _isSealed = 1 << 8;
static const int _isSimplyBounded = 1 << 9;
static void read(SummaryDataReader reader, ClassElementImpl element) {
static void read(
SummaryDataReader reader,
ClassOrAugmentationElementMixin element,
) {
var byte = reader.readUInt30();
element.isAbstract = (byte & _isAbstract) != 0;
element.isBase = (byte & _isBase) != 0;
element.isFinal = (byte & _isFinal) != 0;
element.isInline = (byte & _isInline) != 0;
if (element is ClassElementImpl) {
element.isInline = (byte & _isInline) != 0;
}
element.isInterface = (byte & _isInterface) != 0;
element.isMacro = (byte & _isMacro) != 0;
element.isMixinApplication = (byte & _isMixinApplication) != 0;
if (element is ClassElementImpl) {
element.isMixinApplication = (byte & _isMixinApplication) != 0;
}
element.isMixinClass = (byte & _isMixinClass) != 0;
element.isSealed = (byte & _isSealed) != 0;
element.isSimplyBounded = (byte & _isSimplyBounded) != 0;
if (element is ClassElementImpl) {
element.isSimplyBounded = (byte & _isSimplyBounded) != 0;
}
}
static void write(BufferedSink sink, ClassElementImpl element) {
static void write(
BufferedSink sink,
ClassOrAugmentationElementMixin element,
) {
var result = 0;
result |= element.isAbstract ? _isAbstract : 0;
result |= element.isBase ? _isBase : 0;
result |= element.isFinal ? _isFinal : 0;
result |= element.isInline ? _isInline : 0;
if (element is ClassElementImpl) {
result |= element.isInline ? _isInline : 0;
}
result |= element.isInterface ? _isInterface : 0;
result |= element.isMacro ? _isMacro : 0;
result |= element.isMixinApplication ? _isMixinApplication : 0;
if (element is ClassElementImpl) {
result |= element.isMixinApplication ? _isMixinApplication : 0;
}
result |= element.isMixinClass ? _isMixinClass : 0;
result |= element.isSealed ? _isSealed : 0;
result |= element.isSimplyBounded ? _isSimplyBounded : 0;
if (element is ClassElementImpl) {
result |= element.isSimplyBounded ? _isSimplyBounded : 0;
}
sink.writeUInt30(result);
}
}
@ -260,38 +264,28 @@ class MethodElementFlags {
}
}
class MixinAugmentationElementFlags {
static const int _isBase = 1 << 0;
static void read(
SummaryDataReader reader,
MixinAugmentationElementImpl element,
) {
final byte = reader.readByte();
element.isBase = (byte & _isBase) != 0;
}
static void write(BufferedSink sink, MixinAugmentationElementImpl element) {
var result = 0;
result |= element.isBase ? _isBase : 0;
sink.writeUInt30(result);
}
}
class MixinElementFlags {
static const int _isBase = 1 << 0;
static const int _isSimplyBounded = 1 << 1;
static void read(SummaryDataReader reader, MixinElementImpl element) {
static void read(
SummaryDataReader reader,
MixinOrAugmentationElementMixin element,
) {
var byte = reader.readByte();
element.isBase = (byte & _isBase) != 0;
element.isSimplyBounded = (byte & _isSimplyBounded) != 0;
if (element is MixinElementImpl) {
element.isSimplyBounded = (byte & _isSimplyBounded) != 0;
}
}
static void write(BufferedSink sink, MixinElementImpl element) {
static void write(
BufferedSink sink, MixinOrAugmentationElementMixin element) {
var result = 0;
result |= element.isBase ? _isBase : 0;
result |= element.isSimplyBounded ? _isSimplyBounded : 0;
if (element is MixinElementImpl) {
result |= element.isSimplyBounded ? _isSimplyBounded : 0;
}
sink.writeByte(result);
}
}

View file

@ -536,28 +536,30 @@ class _ElementWriter {
_sink.write('augment ');
}
if (e is ClassElementImpl) {
_sink.writeIf(e.isAbstract, 'abstract ');
_sink.writeIf(e.isMacro, 'macro ');
_sink.writeIf(e.isSealed, 'sealed ');
_sink.writeIf(e.isBase, 'base ');
_sink.writeIf(e.isInterface, 'interface ');
_sink.writeIf(e.isFinal, 'final ');
_sink.writeIf(e.isInline, 'inline ');
_sink.writeIf(e.isMixinClass, 'mixin ');
}
_sink.writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
if (e is EnumElementImpl) {
_sink.write('enum ');
} else if (e is MixinOrAugmentationElementMixin) {
_sink.writeIf(e.isBase, 'base ');
_sink.write('mixin ');
} else {
_sink.write('class ');
}
if (e is ClassElementImpl) {
_sink.writeIf(e.isMixinApplication, 'alias ');
switch (e) {
case ClassOrAugmentationElementMixin():
_sink.writeIf(e.isAbstract, 'abstract ');
_sink.writeIf(e.isMacro, 'macro ');
_sink.writeIf(e.isSealed, 'sealed ');
_sink.writeIf(e.isBase, 'base ');
_sink.writeIf(e.isInterface, 'interface ');
_sink.writeIf(e.isFinal, 'final ');
if (e is ClassElementImpl) {
_sink.writeIf(e.isInline, 'inline ');
}
_sink.writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
_sink.writeIf(e.isMixinClass, 'mixin ');
_sink.write('class ');
if (e is ClassElementImpl) {
_sink.writeIf(e.isMixinApplication, 'alias ');
}
case EnumElementImpl():
_sink.writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
_sink.write('enum ');
case MixinOrAugmentationElementMixin():
_sink.writeIf(e.isBase, 'base ');
_sink.writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
_sink.write('mixin ');
}
_writeName(e);

View file

@ -395,6 +395,216 @@ library
''');
}
test_modifiers_abstract() async {
newFile('$testPackageLibPath/a.dart', r'''
library augment 'test.dart';
augment abstract class A {}
''');
var library = await buildLibrary(r'''
import augment 'a.dart';
abstract class A {}
''');
checkElementText(library, r'''
library
definingUnit
classes
abstract class A @40
augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A
constructors
synthetic @-1
augmented
augmentationImports
package:test/a.dart
definingUnit
classAugmentations
augment abstract class A @52
augmentationTarget: self::@class::A
augmentedDeclaration: self::@class::A
''');
}
test_modifiers_base() async {
newFile('$testPackageLibPath/a.dart', r'''
library augment 'test.dart';
augment base class A {}
''');
var library = await buildLibrary(r'''
import augment 'a.dart';
base class A {}
''');
checkElementText(library, r'''
library
definingUnit
classes
base class A @36
augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A
constructors
synthetic @-1
augmented
augmentationImports
package:test/a.dart
definingUnit
classAugmentations
augment base class A @48
augmentationTarget: self::@class::A
augmentedDeclaration: self::@class::A
''');
}
test_modifiers_final() async {
newFile('$testPackageLibPath/a.dart', r'''
library augment 'test.dart';
augment final class A {}
''');
var library = await buildLibrary(r'''
import augment 'a.dart';
final class A {}
''');
checkElementText(library, r'''
library
definingUnit
classes
final class A @37
augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A
constructors
synthetic @-1
augmented
augmentationImports
package:test/a.dart
definingUnit
classAugmentations
augment final class A @49
augmentationTarget: self::@class::A
augmentedDeclaration: self::@class::A
''');
}
test_modifiers_interface() async {
newFile('$testPackageLibPath/a.dart', r'''
library augment 'test.dart';
augment interface class A {}
''');
var library = await buildLibrary(r'''
import augment 'a.dart';
interface class A {}
''');
checkElementText(library, r'''
library
definingUnit
classes
interface class A @41
augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A
constructors
synthetic @-1
augmented
augmentationImports
package:test/a.dart
definingUnit
classAugmentations
augment interface class A @53
augmentationTarget: self::@class::A
augmentedDeclaration: self::@class::A
''');
}
test_modifiers_macro() async {
newFile('$testPackageLibPath/a.dart', r'''
library augment 'test.dart';
augment macro class A {}
''');
var library = await buildLibrary(r'''
import augment 'a.dart';
macro class A {}
''');
checkElementText(library, r'''
library
definingUnit
classes
macro class A @37
augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A
constructors
synthetic @-1
augmented
augmentationImports
package:test/a.dart
definingUnit
classAugmentations
augment macro class A @49
augmentationTarget: self::@class::A
augmentedDeclaration: self::@class::A
''');
}
test_modifiers_mixin() async {
newFile('$testPackageLibPath/a.dart', r'''
library augment 'test.dart';
augment mixin class A {}
''');
var library = await buildLibrary(r'''
import augment 'a.dart';
mixin class A {}
''');
checkElementText(library, r'''
library
definingUnit
classes
mixin class A @37
augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A
constructors
synthetic @-1
augmented
augmentationImports
package:test/a.dart
definingUnit
classAugmentations
augment mixin class A @49
augmentationTarget: self::@class::A
augmentedDeclaration: self::@class::A
''');
}
test_modifiers_sealed() async {
newFile('$testPackageLibPath/a.dart', r'''
library augment 'test.dart';
augment sealed class A {}
''');
var library = await buildLibrary(r'''
import augment 'a.dart';
sealed class A {}
''');
checkElementText(library, r'''
library
definingUnit
classes
abstract sealed class A @38
augmentation: self::@augmentation::package:test/a.dart::@classAugmentation::A
constructors
synthetic @-1
augmented
augmentationImports
package:test/a.dart
definingUnit
classAugmentations
augment abstract sealed class A @50
augmentationTarget: self::@class::A
augmentedDeclaration: self::@class::A
''');
}
test_notAugmented_interfaces() async {
var library = await buildLibrary(r'''
class A implements I {}