[analyzer] Add mixin classes to ClassElementImpl

Change-Id: I41cbbf218a9c8d7c26fa8f32e3b8022c51b42789
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/275521
Reviewed-by: Konstantin Shcheglov <scheglov@google.com>
Commit-Queue: Kallen Tu <kallentu@google.com>
This commit is contained in:
Kallen Tu 2022-12-15 19:20:06 +00:00 committed by Commit Queue
parent 6d41f47d45
commit 8e1162cb72
8 changed files with 96 additions and 10 deletions

View file

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

View file

@ -194,6 +194,7 @@ class ToSourceVisitor implements AstVisitor<void> {
_visitToken(node.abstractKeyword, suffix: ' '); _visitToken(node.abstractKeyword, suffix: ' ');
_visitToken(node.macroKeyword, suffix: ' '); _visitToken(node.macroKeyword, suffix: ' ');
_visitToken(node.sealedKeyword, suffix: ' '); _visitToken(node.sealedKeyword, suffix: ' ');
_visitToken(node.mixinKeyword, suffix: ' ');
sink.write('class '); sink.write('class ');
_visitToken(node.name); _visitToken(node.name);
_visitNode(node.typeParameters); _visitNode(node.typeParameters);
@ -212,6 +213,7 @@ class ToSourceVisitor implements AstVisitor<void> {
_visitToken(node.abstractKeyword, suffix: ' '); _visitToken(node.abstractKeyword, suffix: ' ');
_visitToken(node.macroKeyword, suffix: ' '); _visitToken(node.macroKeyword, suffix: ' ');
_visitToken(node.sealedKeyword, suffix: ' '); _visitToken(node.sealedKeyword, suffix: ' ');
_visitToken(node.mixinKeyword, suffix: ' ');
sink.write('class '); sink.write('class ');
_visitToken(node.name); _visitToken(node.name);
_visitNode(node.typeParameters); _visitNode(node.typeParameters);

View file

@ -748,6 +748,14 @@ class ClassElementImpl extends ClassOrMixinElementImpl implements ClassElement {
setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication); setModifier(Modifier.MIXIN_APPLICATION, isMixinApplication);
} }
bool get isMixinClass {
return hasModifier(Modifier.MIXIN_CLASS);
}
set isMixinClass(bool isMixinClass) {
setModifier(Modifier.MIXIN_CLASS, isMixinClass);
}
@override @override
bool get isValidMixin { bool get isValidMixin {
final supertype = this.supertype; final supertype = this.supertype;
@ -4841,29 +4849,32 @@ class Modifier implements Comparable<Modifier> {
/// Indicates that a class is a mixin application. /// Indicates that a class is a mixin application.
static const Modifier MIXIN_APPLICATION = Modifier('MIXIN_APPLICATION', 19); static const Modifier MIXIN_APPLICATION = Modifier('MIXIN_APPLICATION', 19);
static const Modifier PROMOTABLE = Modifier('IS_PROMOTABLE', 20); /// Indicates that a class is a mixin class.
static const Modifier MIXIN_CLASS = Modifier('MIXIN_CLASS', 20);
static const Modifier PROMOTABLE = Modifier('IS_PROMOTABLE', 21);
/// Indicates that the modifier 'sealed' was applied to the element. /// Indicates that the modifier 'sealed' was applied to the element.
static const Modifier SEALED = Modifier('SEALED', 21); static const Modifier SEALED = Modifier('SEALED', 22);
/// Indicates that the pseudo-modifier 'set' was applied to the element. /// Indicates that the pseudo-modifier 'set' was applied to the element.
static const Modifier SETTER = Modifier('SETTER', 22); static const Modifier SETTER = Modifier('SETTER', 23);
/// See [TypeParameterizedElement.isSimplyBounded]. /// See [TypeParameterizedElement.isSimplyBounded].
static const Modifier SIMPLY_BOUNDED = Modifier('SIMPLY_BOUNDED', 23); static const Modifier SIMPLY_BOUNDED = Modifier('SIMPLY_BOUNDED', 24);
/// Indicates that the modifier 'static' was applied to the element. /// Indicates that the modifier 'static' was applied to the element.
static const Modifier STATIC = Modifier('STATIC', 24); static const Modifier STATIC = Modifier('STATIC', 25);
/// Indicates that the element does not appear in the source code but was /// Indicates that the element does not appear in the source code but was
/// implicitly created. For example, if a class does not define any /// implicitly created. For example, if a class does not define any
/// constructors, an implicit zero-argument constructor will be created and it /// constructors, an implicit zero-argument constructor will be created and it
/// will be marked as being synthetic. /// will be marked as being synthetic.
static const Modifier SYNTHETIC = Modifier('SYNTHETIC', 25); static const Modifier SYNTHETIC = Modifier('SYNTHETIC', 26);
/// Indicates that the element was appended to this enclosing element to /// Indicates that the element was appended to this enclosing element to
/// simulate temporary the effect of applying augmentation. /// simulate temporary the effect of applying augmentation.
static const Modifier TEMP_AUGMENTATION = Modifier('TEMP_AUGMENTATION', 26); static const Modifier TEMP_AUGMENTATION = Modifier('TEMP_AUGMENTATION', 27);
static const List<Modifier> values = [ static const List<Modifier> values = [
ABSTRACT, ABSTRACT,
@ -4885,6 +4896,7 @@ class Modifier implements Comparable<Modifier> {
LATE, LATE,
MACRO, MACRO,
MIXIN_APPLICATION, MIXIN_APPLICATION,
MIXIN_CLASS,
PROMOTABLE, PROMOTABLE,
SEALED, SEALED,
SETTER, SETTER,

View file

@ -95,6 +95,7 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
element.isSealed = true; element.isSealed = true;
element.isAbstract = true; element.isAbstract = true;
} }
element.isMixinClass = node.mixinKeyword != null;
element.metadata = _buildAnnotations(node.metadata); element.metadata = _buildAnnotations(node.metadata);
_setCodeRange(element, node); _setCodeRange(element, node);
_setDocumentation(element, node); _setDocumentation(element, node);
@ -133,6 +134,7 @@ class ElementBuilder extends ThrowingAstVisitor<void> {
element.isAbstract = true; element.isAbstract = true;
} }
element.isMixinApplication = true; element.isMixinApplication = true;
element.isMixinClass = node.mixinKeyword != null;
element.metadata = _buildAnnotations(node.metadata); element.metadata = _buildAnnotations(node.metadata);
_setCodeRange(element, node); _setCodeRange(element, node);
_setDocumentation(element, node); _setDocumentation(element, node);

View file

@ -10,14 +10,16 @@ class ClassElementFlags {
static const int _isAbstract = 1 << 0; static const int _isAbstract = 1 << 0;
static const int _isMacro = 1 << 1; static const int _isMacro = 1 << 1;
static const int _isMixinApplication = 1 << 2; static const int _isMixinApplication = 1 << 2;
static const int _isSealed = 1 << 3; static const int _isMixinClass = 1 << 3;
static const int _isSimplyBounded = 1 << 4; static const int _isSealed = 1 << 4;
static const int _isSimplyBounded = 1 << 5;
static void read(SummaryDataReader reader, ClassElementImpl element) { static void read(SummaryDataReader reader, ClassElementImpl element) {
var byte = reader.readByte(); var byte = reader.readByte();
element.isAbstract = (byte & _isAbstract) != 0; element.isAbstract = (byte & _isAbstract) != 0;
element.isMacro = (byte & _isMacro) != 0; element.isMacro = (byte & _isMacro) != 0;
element.isMixinApplication = (byte & _isMixinApplication) != 0; element.isMixinApplication = (byte & _isMixinApplication) != 0;
element.isMixinClass = (byte & _isMixinClass) != 0;
element.isSealed = (byte & _isSealed) != 0; element.isSealed = (byte & _isSealed) != 0;
element.isSimplyBounded = (byte & _isSimplyBounded) != 0; element.isSimplyBounded = (byte & _isSimplyBounded) != 0;
} }
@ -27,6 +29,7 @@ class ClassElementFlags {
result |= element.isAbstract ? _isAbstract : 0; result |= element.isAbstract ? _isAbstract : 0;
result |= element.isMacro ? _isMacro : 0; result |= element.isMacro ? _isMacro : 0;
result |= element.isMixinApplication ? _isMixinApplication : 0; result |= element.isMixinApplication ? _isMixinApplication : 0;
result |= element.isMixinClass ? _isMixinClass : 0;
result |= element.isSealed ? _isSealed : 0; result |= element.isSealed ? _isSealed : 0;
result |= element.isSimplyBounded ? _isSimplyBounded : 0; result |= element.isSimplyBounded ? _isSimplyBounded : 0;
sink.writeByte(result); sink.writeByte(result);

View file

@ -437,6 +437,16 @@ macro class A {}
); );
} }
void test_visitClassDeclaration_mixin() {
var findNode = _parseStringToFindNode(r'''
mixin class A {}
''');
_assertSource(
'mixin class A {}',
findNode.classDeclaration('class A'),
);
}
void test_visitClassDeclaration_multipleMember() { void test_visitClassDeclaration_multipleMember() {
final code = 'class C {var a; var b;}'; final code = 'class C {var a; var b;}';
final findNode = _parseStringToFindNode(''' final findNode = _parseStringToFindNode('''
@ -590,6 +600,16 @@ $code
_assertSource(code, findNode.classTypeAlias(code)); _assertSource(code, findNode.classTypeAlias(code));
} }
void test_visitClassTypeAlias_mixin() {
var findNode = _parseStringToFindNode(r'''
mixin class A = S with M;
''');
_assertSource(
'mixin class A = S with M;',
findNode.classTypeAlias('class A'),
);
}
void test_visitClassTypeAlias_parameters_abstract() { void test_visitClassTypeAlias_parameters_abstract() {
final code = 'abstract class C<E> = S with M;'; final code = 'abstract class C<E> = S with M;';
final findNode = _parseStringToFindNode(''' final findNode = _parseStringToFindNode('''

View file

@ -291,6 +291,7 @@ class _ElementWriter {
_writeIf(e.isAbstract, 'abstract '); _writeIf(e.isAbstract, 'abstract ');
_writeIf(e.isMacro, 'macro '); _writeIf(e.isMacro, 'macro ');
_writeIf(e.isSealed, 'sealed '); _writeIf(e.isSealed, 'sealed ');
_writeIf(e.isMixinClass, 'mixin ');
} }
_writeIf(!e.isSimplyBounded, 'notSimplyBounded '); _writeIf(!e.isSimplyBounded, 'notSimplyBounded ');
@ -1088,6 +1089,11 @@ extension on ClassElement {
return self is ClassElementImpl && self.isMacro; return self is ClassElementImpl && self.isMacro;
} }
bool get isMixinClass {
final self = this;
return self is ClassElementImpl && self.isMixinClass;
}
bool get isSealed { bool get isSealed {
final self = this; final self = this;
return self is ClassElementImpl && self.isSealed; return self is ClassElementImpl && self.isSealed;

View file

@ -6828,6 +6828,18 @@ library
'''); ''');
} }
test_class_mixin_class() async {
var library = await buildLibrary('mixin class C {}');
checkElementText(library, r'''
library
definingUnit
classes
mixin class C @12
constructors
synthetic @-1
''');
}
test_class_mixins() async { test_class_mixins() async {
var library = await buildLibrary(''' var library = await buildLibrary('''
class C extends D with E, F, G {} class C extends D with E, F, G {}
@ -8931,6 +8943,35 @@ library
'''); ''');
} }
test_classAlias_mixin_class() async {
var library = await buildLibrary('''
mixin class C = Object with M;
mixin M {}
''');
checkElementText(library, r'''
library
definingUnit
classes
mixin class alias C @12
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 @37
superclassConstraints
Object
''');
}
test_classAlias_notSimplyBounded_self() async { test_classAlias_notSimplyBounded_self() async {
var library = await buildLibrary(''' var library = await buildLibrary('''
class C<T extends C> = D with E; class C<T extends C> = D with E;