mirror of
https://github.com/dart-lang/sdk
synced 2024-09-16 00:19:48 +00:00
[analyzer] Add sealed modifier to ClassOrMixinElementImpl and source visitor.
Add sealed modifier to element builder summaries and to_source_visitor. Enable sealed_class experiement in tests to test the changes. Change-Id: I2929a5a38360c73abfcdb26d1e9b786058ea9335 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/272351 Commit-Queue: Kallen Tu <kallentu@google.com> Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
This commit is contained in:
parent
c870932e45
commit
1d9257ad02
|
@ -85,7 +85,7 @@ import 'package:analyzer/src/util/performance/operation_performance.dart';
|
|||
/// TODO(scheglov) Clean up the list of implicitly analyzed files.
|
||||
class AnalysisDriver implements AnalysisDriverGeneric {
|
||||
/// The version of data format, should be incremented on every format change.
|
||||
static const int DATA_VERSION = 250;
|
||||
static const int DATA_VERSION = 251;
|
||||
|
||||
/// The number of exception contexts allowed to write. Once this field is
|
||||
/// zero, we stop writing any new exception contexts in this process.
|
||||
|
|
|
@ -188,6 +188,7 @@ class ToSourceVisitor implements AstVisitor<void> {
|
|||
_visitToken(node.augmentKeyword, suffix: ' ');
|
||||
_visitToken(node.abstractKeyword, suffix: ' ');
|
||||
_visitToken(node.macroKeyword, suffix: ' ');
|
||||
_visitToken(node.sealedKeyword, suffix: ' ');
|
||||
sink.write('class ');
|
||||
_visitToken(node.name);
|
||||
_visitNode(node.typeParameters);
|
||||
|
@ -205,6 +206,7 @@ class ToSourceVisitor implements AstVisitor<void> {
|
|||
_visitToken(node.augmentKeyword, suffix: ' ');
|
||||
_visitToken(node.abstractKeyword, suffix: ' ');
|
||||
_visitToken(node.macroKeyword, suffix: ' ');
|
||||
_visitToken(node.sealedKeyword, suffix: ' ');
|
||||
sink.write('class ');
|
||||
_visitToken(node.name);
|
||||
_visitNode(node.typeParameters);
|
||||
|
|
|
@ -998,6 +998,14 @@ abstract class ClassOrMixinElementImpl extends AbstractClassElementImpl {
|
|||
return _interfaces;
|
||||
}
|
||||
|
||||
bool get isSealed {
|
||||
return hasModifier(Modifier.SEALED);
|
||||
}
|
||||
|
||||
set isSealed(bool isSealed) {
|
||||
setModifier(Modifier.SEALED, isSealed);
|
||||
}
|
||||
|
||||
@override
|
||||
bool get isSimplyBounded {
|
||||
return hasModifier(Modifier.SIMPLY_BOUNDED);
|
||||
|
@ -4839,24 +4847,27 @@ class Modifier implements Comparable<Modifier> {
|
|||
|
||||
static const Modifier PROMOTABLE = Modifier('IS_PROMOTABLE', 20);
|
||||
|
||||
/// Indicates that the modifier 'sealed' was applied to the element.
|
||||
static const Modifier SEALED = Modifier('SEALED', 21);
|
||||
|
||||
/// Indicates that the pseudo-modifier 'set' was applied to the element.
|
||||
static const Modifier SETTER = Modifier('SETTER', 21);
|
||||
static const Modifier SETTER = Modifier('SETTER', 22);
|
||||
|
||||
/// See [TypeParameterizedElement.isSimplyBounded].
|
||||
static const Modifier SIMPLY_BOUNDED = Modifier('SIMPLY_BOUNDED', 22);
|
||||
static const Modifier SIMPLY_BOUNDED = Modifier('SIMPLY_BOUNDED', 23);
|
||||
|
||||
/// Indicates that the modifier 'static' was applied to the element.
|
||||
static const Modifier STATIC = Modifier('STATIC', 23);
|
||||
static const Modifier STATIC = Modifier('STATIC', 24);
|
||||
|
||||
/// Indicates that the element does not appear in the source code but was
|
||||
/// implicitly created. For example, if a class does not define any
|
||||
/// constructors, an implicit zero-argument constructor will be created and it
|
||||
/// will be marked as being synthetic.
|
||||
static const Modifier SYNTHETIC = Modifier('SYNTHETIC', 24);
|
||||
static const Modifier SYNTHETIC = Modifier('SYNTHETIC', 25);
|
||||
|
||||
/// Indicates that the element was appended to this enclosing element to
|
||||
/// simulate temporary the effect of applying augmentation.
|
||||
static const Modifier TEMP_AUGMENTATION = Modifier('TEMP_AUGMENTATION', 25);
|
||||
static const Modifier TEMP_AUGMENTATION = Modifier('TEMP_AUGMENTATION', 26);
|
||||
|
||||
static const List<Modifier> values = [
|
||||
ABSTRACT,
|
||||
|
@ -4879,6 +4890,7 @@ class Modifier implements Comparable<Modifier> {
|
|||
MACRO,
|
||||
MIXIN_APPLICATION,
|
||||
PROMOTABLE,
|
||||
SEALED,
|
||||
SETTER,
|
||||
STATIC,
|
||||
SIMPLY_BOUNDED,
|
||||
|
|
|
@ -91,6 +91,7 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
|
|||
var element = ClassElementImpl(name, nameToken.offset);
|
||||
element.isAbstract = node.abstractKeyword != null;
|
||||
element.isMacro = node.macroKeyword != null;
|
||||
element.isSealed = node.sealedKeyword != null;
|
||||
element.metadata = _buildAnnotations(node.metadata);
|
||||
_setCodeRange(element, node);
|
||||
_setDocumentation(element, node);
|
||||
|
@ -124,6 +125,7 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
|
|||
var element = ClassElementImpl(name, nameToken.offset);
|
||||
element.isAbstract = node.abstractKeyword != null;
|
||||
element.isMacro = node.macroKeyword != null;
|
||||
element.isSealed = node.sealedKeyword != null;
|
||||
element.isMixinApplication = true;
|
||||
element.metadata = _buildAnnotations(node.metadata);
|
||||
_setCodeRange(element, node);
|
||||
|
@ -848,6 +850,7 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
|
|||
var name = nameToken.lexeme;
|
||||
|
||||
var element = MixinElementImpl(name, nameToken.offset);
|
||||
element.isSealed = node.sealedKeyword != null;
|
||||
element.metadata = _buildAnnotations(node.metadata);
|
||||
_setCodeRange(element, node);
|
||||
_setDocumentation(element, node);
|
||||
|
|
|
@ -10,13 +10,15 @@ class ClassElementFlags {
|
|||
static const int _isAbstract = 1 << 0;
|
||||
static const int _isMacro = 1 << 1;
|
||||
static const int _isMixinApplication = 1 << 2;
|
||||
static const int _isSimplyBounded = 1 << 3;
|
||||
static const int _isSealed = 1 << 3;
|
||||
static const int _isSimplyBounded = 1 << 4;
|
||||
|
||||
static void read(SummaryDataReader reader, ClassElementImpl element) {
|
||||
var byte = reader.readByte();
|
||||
element.isAbstract = (byte & _isAbstract) != 0;
|
||||
element.isMacro = (byte & _isMacro) != 0;
|
||||
element.isMixinApplication = (byte & _isMixinApplication) != 0;
|
||||
element.isSealed = (byte & _isSealed) != 0;
|
||||
element.isSimplyBounded = (byte & _isSimplyBounded) != 0;
|
||||
}
|
||||
|
||||
|
@ -25,6 +27,7 @@ class ClassElementFlags {
|
|||
result |= element.isAbstract ? _isAbstract : 0;
|
||||
result |= element.isMacro ? _isMacro : 0;
|
||||
result |= element.isMixinApplication ? _isMixinApplication : 0;
|
||||
result |= element.isSealed ? _isSealed : 0;
|
||||
result |= element.isSimplyBounded ? _isSimplyBounded : 0;
|
||||
sink.writeByte(result);
|
||||
}
|
||||
|
@ -223,15 +226,18 @@ class MethodElementFlags {
|
|||
}
|
||||
|
||||
class MixinElementFlags {
|
||||
static const int _isSimplyBounded = 1 << 0;
|
||||
static const int _isSealed = 1 << 0;
|
||||
static const int _isSimplyBounded = 1 << 1;
|
||||
|
||||
static void read(SummaryDataReader reader, MixinElementImpl element) {
|
||||
var byte = reader.readByte();
|
||||
element.isSealed = (byte & _isSealed) != 0;
|
||||
element.isSimplyBounded = (byte & _isSimplyBounded) != 0;
|
||||
}
|
||||
|
||||
static void write(BufferedSink sink, MixinElementImpl element) {
|
||||
var result = 0;
|
||||
result |= element.isSealed ? _isSealed : 0;
|
||||
result |= element.isSimplyBounded ? _isSimplyBounded : 0;
|
||||
sink.writeByte(result);
|
||||
}
|
||||
|
|
|
@ -482,6 +482,16 @@ $code
|
|||
_assertSource(code, findNode.classDeclaration(code));
|
||||
}
|
||||
|
||||
void test_visitClassDeclaration_sealed() {
|
||||
var findNode = _parseStringToFindNode(r'''
|
||||
sealed class A {}
|
||||
''');
|
||||
_assertSource(
|
||||
'sealed class A {}',
|
||||
findNode.classDeclaration('class A'),
|
||||
);
|
||||
}
|
||||
|
||||
void test_visitClassDeclaration_singleMember() {
|
||||
final code = 'class C {var a;}';
|
||||
final findNode = _parseStringToFindNode(code);
|
||||
|
@ -595,6 +605,16 @@ $code
|
|||
_assertSource(code, findNode.classTypeAlias(code));
|
||||
}
|
||||
|
||||
void test_visitClassTypeAlias_sealed() {
|
||||
var findNode = _parseStringToFindNode(r'''
|
||||
sealed class A = S with M;
|
||||
''');
|
||||
_assertSource(
|
||||
'sealed class A = S with M;',
|
||||
findNode.classTypeAlias('class A'),
|
||||
);
|
||||
}
|
||||
|
||||
void test_visitClassTypeAlias_withMetadata() {
|
||||
final code = '@deprecated class A = S with M;';
|
||||
final findNode = _parseStringToFindNode(code);
|
||||
|
|
|
@ -325,6 +325,7 @@ class PubPackageResolutionTest extends ContextResolutionTest {
|
|||
EnableString.macros,
|
||||
EnableString.patterns,
|
||||
EnableString.records,
|
||||
EnableString.sealed_class,
|
||||
];
|
||||
|
||||
@override
|
||||
|
|
|
@ -290,12 +290,14 @@ class _ElementWriter {
|
|||
if (e is ClassElement) {
|
||||
_writeIf(e.isAbstract, 'abstract ');
|
||||
_writeIf(e.isMacro, 'macro ');
|
||||
_writeIf(e.isSealed, 'sealed ');
|
||||
}
|
||||
_writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
|
||||
|
||||
if (e is EnumElement) {
|
||||
buffer.write('enum ');
|
||||
} else if (e is MixinElement) {
|
||||
_writeIf(e.isSealed, 'sealed ');
|
||||
buffer.write('mixin ');
|
||||
} else {
|
||||
buffer.write('class ');
|
||||
|
@ -1085,4 +1087,16 @@ extension on ClassElement {
|
|||
final self = this;
|
||||
return self is ClassElementImpl && self.isMacro;
|
||||
}
|
||||
|
||||
bool get isSealed {
|
||||
final self = this;
|
||||
return self is ClassElementImpl && self.isSealed;
|
||||
}
|
||||
}
|
||||
|
||||
extension on MixinElement {
|
||||
bool get isSealed {
|
||||
final self = this;
|
||||
return self is MixinElementImpl && self.isSealed;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7570,6 +7570,18 @@ library
|
|||
''');
|
||||
}
|
||||
|
||||
test_class_sealed() async {
|
||||
var library = await buildLibrary('sealed class C {}');
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
definingUnit
|
||||
classes
|
||||
sealed class C @13
|
||||
constructors
|
||||
synthetic @-1
|
||||
''');
|
||||
}
|
||||
|
||||
test_class_setter_abstract() async {
|
||||
var library =
|
||||
await buildLibrary('abstract class C { void set x(int value); }');
|
||||
|
@ -9031,6 +9043,35 @@ library
|
|||
''');
|
||||
}
|
||||
|
||||
test_classAlias_sealed() async {
|
||||
var library = await buildLibrary('''
|
||||
sealed class C = Object with M;
|
||||
mixin M {}
|
||||
''');
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
definingUnit
|
||||
classes
|
||||
sealed class alias C @13
|
||||
supertype: Object
|
||||
mixins
|
||||
M
|
||||
constructors
|
||||
synthetic const @-1
|
||||
constantInitializers
|
||||
SuperConstructorInvocation
|
||||
superKeyword: super @0
|
||||
argumentList: ArgumentList
|
||||
leftParenthesis: ( @0
|
||||
rightParenthesis: ) @0
|
||||
staticElement: dart:core::@class::Object::@constructor::new
|
||||
mixins
|
||||
mixin M @38
|
||||
superclassConstraints
|
||||
Object
|
||||
''');
|
||||
}
|
||||
|
||||
test_classAlias_with_const_constructors() async {
|
||||
addSource('$testPackageLibPath/a.dart', r'''
|
||||
class Base {
|
||||
|
@ -34207,6 +34248,20 @@ library
|
|||
''');
|
||||
}
|
||||
|
||||
test_mixin_sealed() async {
|
||||
var library = await buildLibrary(r'''
|
||||
sealed mixin M on A {}
|
||||
''');
|
||||
checkElementText(library, r'''
|
||||
library
|
||||
definingUnit
|
||||
mixins
|
||||
sealed mixin M @13
|
||||
superclassConstraints
|
||||
Object
|
||||
''');
|
||||
}
|
||||
|
||||
test_mixin_setter_invokesSuperSelf_getter() async {
|
||||
var library = await buildLibrary(r'''
|
||||
mixin M on A {
|
||||
|
|
Loading…
Reference in a new issue